Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/gaia/apps/webui/services/backend-installer.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,16 @@ const NETWORK_CHECK_TIMEOUT_MS = 5000;
// contributors running from source keep working.
//
// When bumping uv, update BOTH:
// - .github/workflows/build-installers.yml (download pin + sha256)
// - BUNDLED_UV_SHA256 below (matches CI)
// - .github/workflows/build-installers.yml (tarball .tar.gz SHA256 — archive)
// - BUNDLED_UV_SHA256 below (extracted ELF binary SHA256)
// These are two different digests: the workflow verifies the downloaded
// archive against upstream's published .sha256, then extracts the `uv` binary
// which is what `ensureUv()` hashes at runtime.
//
// Currently pinned: uv v0.5.14 linux-x64.
const BUNDLED_UV_VERSION = "0.5.14";
const BUNDLED_UV_SHA256 = {
"linux-x64": "22034760075b92487b326da5aa1a2a3e1917e2e766c12c0fd466fccda77013c7",
"linux-x64": "0e05d828b5708e8a927724124db3746396afddad6273c47283d7c562dc795bd6",
};

const MANAGED_UV_DIR = path.join(GAIA_HOME, "bin");
Expand Down
44 changes: 44 additions & 0 deletions tests/electron/appimage-smoke.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import test from "node:test";
import assert from "node:assert/strict";
import { execFileSync, spawnSync } from "node:child_process";
import crypto from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down Expand Up @@ -141,6 +142,49 @@ if (!APPIMAGE) {
);
});

// ── AC4 / T3b: bundled uv binary SHA256 matches BUNDLED_UV_SHA256 ──
// Runtime ensureUv() hashes the extracted ELF and rejects any mismatch,
// so catch packaging/hash drift at smoke time instead of on user launch.
test("AC4/T3b: bundled uv SHA256 matches BUNDLED_UV_SHA256[linux-x64]", () => {
const uvPath = path.join(
squashRoot,
"resources",
"vendor",
"uv",
"linux-x64",
"uv"
);
const installerPath = path.resolve(
path.dirname(new URL(import.meta.url).pathname),
"..",
"..",
"src",
"gaia",
"apps",
"webui",
"services",
"backend-installer.cjs"
);
const installerSrc = fs.readFileSync(installerPath, "utf8");
const m = installerSrc.match(
/BUNDLED_UV_SHA256\s*=\s*\{[^}]*?"linux-x64"\s*:\s*"([0-9a-f]{64})"/s
);
assert.ok(
m,
`could not parse BUNDLED_UV_SHA256["linux-x64"] from ${installerPath}`
);
const expected = m[1];
const actual = crypto
.createHash("sha256")
.update(fs.readFileSync(uvPath))
.digest("hex");
assert.equal(
actual,
expected,
`bundled uv binary SHA256 does not match BUNDLED_UV_SHA256["linux-x64"]; ensureUv() will reject this at runtime`
);
});

// ── AC3: pre-built React dist/ ships with the AppImage ──────────
test("AC3: pre-built dist/index.html is present in resources", () => {
const indexHtml = path.join(
Expand Down
Loading