// node --test scripts/ci/lib/runtime-feed-gate.test.mjs import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { test } from "node:test"; import { fileURLToPath, URL } from "node:url"; import { RUNTIME_MIN_VERSION_SOURCE, WINDOWS_X64_TARGET, assertRuntimeFeedCompatible, evaluateRuntimeFeed, parseRuntimeMinVersions, } from "./runtime-feed-gate.mjs"; import { buildRuntimeIndex } from "./runtime-index-builder.mjs"; const SHA = "a".repeat(64); const MIN = { sidecar: "1.7.0", ffmpeg: null }; function index({ version = "1.9.0", platform = "win32", arch = "x64", components = ["sidecar", "ffmpeg"] } = {}) { return buildRuntimeIndex({ version, generatedAt: "2026-09-28T00:00:00.000Z", platform, arch, partBaseUrl: `https://feed.test/runtime-${version}`, components: Object.fromEntries( components.map((name) => [ name, { archive: `d3ro-runtime-${name}.tar.gz`, sha256: SHA, totalSize: 10, parts: [{ name: `d3ro-runtime-${name}.tar.gz.001`, size: 10, sha256: SHA }], }, ]), ), }); } function jsonFetch(body, status = 200) { const calls = []; const fetchImpl = async (url) => { calls.push(url); return new Response(JSON.stringify(body), { status }); }; return { fetchImpl, calls }; } test("parseRuntimeMinVersions reads the app's real RUNTIME_MIN_VERSION (drift guard)", () => { const source = readFileSync(fileURLToPath(new URL(`../../../${RUNTIME_MIN_VERSION_SOURCE}`, import.meta.url)), "utf8"); const parsed = parseRuntimeMinVersions(source); assert.deepEqual(Object.keys(parsed).sort(), ["ffmpeg", "sidecar"]); assert.match(parsed.sidecar, /^\d+\.\d+\.\d+$/); assert.equal(parsed.ffmpeg, null); }); test("parseRuntimeMinVersions fails loudly when the constant cannot be read", () => { assert.throws(() => parseRuntimeMinVersions("export const OTHER = {}"), /RUNTIME_MIN_VERSION not found/); assert.throws( () => parseRuntimeMinVersions("export const RUNTIME_MIN_VERSION = {\n sidecar: '1.7',\n}"), /not semver/, ); }); test("a runtime feed that satisfies the minimum and target passes", () => { assert.deepEqual(evaluateRuntimeFeed({ index: index(), minVersions: MIN, target: WINDOWS_X64_TARGET }), []); }); test("runtime-latest older than this build's minimum blocks latest.yml (regression)", () => { const problems = evaluateRuntimeFeed({ index: index({ version: "1.6.0" }), minVersions: MIN, target: WINDOWS_X64_TARGET, }); assert.equal(problems.length, 1); assert.match(problems[0], /1\.6\.0 is below .*sidecar 1\.7\.0/); }); test("a legacy index without platform/arch or for another platform is rejected", () => { const legacy = index(); delete legacy.platform; delete legacy.arch; assert.match( evaluateRuntimeFeed({ index: legacy, minVersions: MIN, target: WINDOWS_X64_TARGET }).join("\n"), /does not declare platform\/arch/, ); assert.match( evaluateRuntimeFeed({ index: index({ platform: "darwin", arch: "arm64" }), minVersions: MIN, target: WINDOWS_X64_TARGET }).join("\n"), /targets darwin-arm64/, ); }); test("a missing component is rejected even without a minimum version", () => { const problems = evaluateRuntimeFeed({ index: index({ components: ["sidecar"] }), minVersions: MIN, target: WINDOWS_X64_TARGET, }); assert.deepEqual(problems, ["runtime.json has no ffmpeg component"]); }); test("assertRuntimeFeedCompatible fails closed when the feed is unreadable", async () => { const missing = jsonFetch({}, 404); await assert.rejects( assertRuntimeFeedCompatible({ url: "https://feed.test/runtime-latest/runtime.json", fetchImpl: missing.fetchImpl, minVersions: MIN }), /cannot read .*HTTP 404/, ); const failing = async () => { throw new Error("offline"); }; await assert.rejects( assertRuntimeFeedCompatible({ url: "https://feed.test/x", fetchImpl: failing, minVersions: MIN }), /cannot read .*offline/, ); }); test("assertRuntimeFeedCompatible returns the feed version when compatible and throws when stale", async () => { const ok = jsonFetch(index({ version: "1.9.0" })); assert.deepEqual( await assertRuntimeFeedCompatible({ url: "https://feed.test/runtime.json", fetchImpl: ok.fetchImpl, minVersions: MIN }), { version: "1.9.0" }, ); assert.deepEqual(ok.calls, ["https://feed.test/runtime.json"]); const stale = jsonFetch(index({ version: "1.6.0" })); await assert.rejects( assertRuntimeFeedCompatible({ url: "https://feed.test/runtime.json", fetchImpl: stale.fetchImpl, minVersions: MIN }), /refusing to publish latest\.yml[\s\S]*1\.6\.0 is below/, ); });