Skip to content

Commit 0dacb1d

Browse files
gitcommit90claude
andcommitted
fix: point the website's offline release fallback at 0.0.38
site/server.mjs serves RELEASE_FALLBACK whenever GitHub's release API is unreachable or rate limited. It was still pinned to v0.0.30 with that release's digests, so any API hiccup would quietly hand every visitor a build eight patches old from the download buttons - a failure that is invisible until someone reports installing the wrong version. Updates the tag and all six artifact digests to the verified 0.0.38 artifacts, and derives the download URLs from a single tag constant so the tag and the URLs cannot drift apart. Adds a regression test that fails when the fallback goes stale: the tag must equal package.json, all five desktop artifacts must be named for the shipping version, and all six digests must be present and distinct. The existing offline-metadata contract hardcoded 0.0.30 as its expected answer, which would have kept passing against a stale fallback forever, so it now derives the expected version from package.json too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent ab97ecd commit 0dacb1d

2 files changed

Lines changed: 45 additions & 13 deletions

File tree

site/server.mjs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,26 @@ const ORIGIN = "https://1helm.com";
3030
const REPO = "gitcommit90/1Helm";
3131
const RELEASE_PAGE = `https://github.com/${REPO}/releases/latest`;
3232
const RELEASE_CACHE_MS = 10 * 60_000;
33+
// Served only when GitHub's release API is unreachable or rate limited. It
34+
// must name the current release: a stale fallback silently hands visitors an
35+
// older build from the download links. Update the tag and all six digests in
36+
// the same commit that ships a release.
37+
const RELEASE_FALLBACK_TAG = "v0.0.38";
3338
const RELEASE_FALLBACK = {
34-
tag_name: "v0.0.30",
39+
tag_name: RELEASE_FALLBACK_TAG,
3540
draft: false,
3641
prerelease: false,
3742
assets: [
38-
["1Helm-0.0.30-arm64.dmg", "597bccdf464e397389511100f254b40b3da266a52e00049d4553bf5476440bcb"],
39-
["1Helm-0.0.30-mac-arm64.zip", "54729c10aee1173f1f4b085826bdfe9838f37dfc61f3999ff8d073e39ccc4e94"],
40-
["1Helm-0.0.30-linux-node.tgz", "d96cb1bbc73686562dbff3c797cbd8fcc8962c8cc97602edd1fabf1b1e2e5d64"],
41-
["1Helm-0.0.30-windows-x64-setup.exe", "ff5b2fa32ea916b88dc08164bb52a55253d9921f73f713b1413bbf4ac1d4669f"],
42-
["1Helm-0.0.30-full.nupkg", "3142069585e3a02290fc8092ff8e1e80683c355aa1e78d2871260f1518ea83bf"],
43-
["RELEASES", "11bc1746bca8f6414f8dd6df254bfcf921dec13ca72b037c03c47152db30f542"],
43+
["1Helm-0.0.38-arm64.dmg", "468a5b8d59a23c4419331db20dcdb955f088a046add48296b5d5aa8450120527"],
44+
["1Helm-0.0.38-mac-arm64.zip", "4135defe285f9d7e480802d17d81ff37d083a90f6d7dc928f7061a73f9861302"],
45+
["1Helm-0.0.38-linux-node.tgz", "12d59534b66c325891d5433eb2c7ab8990ee67c9d56a805b65b9633030c424fc"],
46+
["1Helm-0.0.38-windows-x64-setup.exe", "0689afadc996319a22d6a3419d39725453bc46d9bdd8857463a56b7bcf738590"],
47+
["1Helm-0.0.38-full.nupkg", "2b25a71f6b3bbb96d7a62cca4bdbd421daed22a1005b1e93d31a77b3d61e86ae"],
48+
["RELEASES", "a20bf26fc174a48a2ccd30c4b7ab0289d72c00489761981c89a7eb3c9842f454"],
4449
].map(([name, digest]) => ({
4550
name,
4651
digest: `sha256:${digest}`,
47-
browser_download_url: `https://github.com/${REPO}/releases/download/v0.0.30/${name}`,
52+
browser_download_url: `https://github.com/${REPO}/releases/download/${RELEASE_FALLBACK_TAG}/${name}`,
4853
})),
4954
};
5055
const FEEDBACK_DATA_DIR = resolve(process.env.SITE_DATA_DIR || join(ROOT, ".site-data"));

test/site.mjs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,14 @@ test("release metadata stays available when GitHub's unauthenticated API is exha
112112
await waitFor(`${base}/health`);
113113
const response = await fetch(`${base}/api/releases/linux/latest`);
114114
assert.equal(response.status, 200);
115-
assert.deepEqual(await response.json(), {
116-
version: "0.0.30",
117-
url: "https://github.com/gitcommit90/1Helm/releases/download/v0.0.30/1Helm-0.0.30-linux-node.tgz",
118-
sha256: "d96cb1bbc73686562dbff3c797cbd8fcc8962c8cc97602edd1fabf1b1e2e5d64",
119-
});
115+
// Derived from package.json rather than pinned: the point of this contract
116+
// is that the offline fallback serves the SHIPPING release, so hardcoding a
117+
// version here would keep passing while the fallback silently went stale.
118+
const version = JSON.parse(readFileSync(join(root, "package.json"), "utf8")).version;
119+
const offline = await response.json();
120+
assert.equal(offline.version, version, "the offline fallback serves the shipping version");
121+
assert.equal(offline.url, `https://github.com/gitcommit90/1Helm/releases/download/v${version}/1Helm-${version}-linux-node.tgz`);
122+
assert.match(offline.sha256, /^[a-f0-9]{64}$/, "the offline fallback carries a real digest");
120123
} finally {
121124
child.kill("SIGTERM");
122125
await new Promise((resolve) => child.once("exit", resolve));
@@ -305,3 +308,27 @@ test("autonomy report names its deterministic scope and live-system limits", ()
305308
assert.match(report.scope.validates.join(" "), /wakeable recurring-work persistence/);
306309
assert.match(report.scope.does_not_validate.join(" "), /live model or provider/);
307310
});
311+
312+
test("the website's offline release fallback names the shipping version", () => {
313+
// This fallback is served when GitHub's release API is unreachable or rate
314+
// limited. A stale entry does not fail loudly — it quietly hands every
315+
// visitor an older build from the download links, which is exactly how a
316+
// release goes out with the previous version behind the buttons.
317+
const version = JSON.parse(readFileSync(join(root, "package.json"), "utf8")).version;
318+
const server = readFileSync(join(root, "site", "server.mjs"), "utf8");
319+
const block = server.match(/const RELEASE_FALLBACK = \{[\s\S]*?\n\};/)?.[0];
320+
assert.ok(block, "site/server.mjs still exposes a release fallback block");
321+
assert.match(server, new RegExp(`RELEASE_FALLBACK_TAG = "v${version.replaceAll(".", "\\.")}"`), "the fallback tag matches package.json");
322+
for (const asset of [
323+
`1Helm-${version}-arm64.dmg`,
324+
`1Helm-${version}-mac-arm64.zip`,
325+
`1Helm-${version}-linux-node.tgz`,
326+
`1Helm-${version}-windows-x64-setup.exe`,
327+
`1Helm-${version}-full.nupkg`,
328+
]) {
329+
assert.ok(block.includes(asset), `the release fallback names ${asset}`);
330+
}
331+
const digests = [...block.matchAll(/"([a-f0-9]{64})"/g)].map((m) => m[1]);
332+
assert.equal(digests.length, 6, "all six desktop artifacts carry a fallback digest");
333+
assert.equal(new Set(digests).size, 6, "no two fallback digests are duplicated");
334+
});

0 commit comments

Comments
 (0)