// node --test scripts/ci/lib/update-policy-schema.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 { assertValidUpdatePolicy, validateUpdatePolicyDocument } from "./update-policy-schema.mjs"; const committedRaw = readFileSync(fileURLToPath(new URL("../../../release/update-policy.json", import.meta.url)), "utf8"); const committed = JSON.parse(committedRaw); test("the committed release/update-policy.json passes the strict schema", () => { assert.deepEqual(validateUpdatePolicyDocument(committed), []); assert.deepEqual(assertValidUpdatePolicy(committedRaw), committed); }); for (const [field, value, pattern] of [ ["stagingPercentage", 5.5, /stagingPercentage/], ["stagingPercentage", "5", /stagingPercentage/], ["stagingPercentage", 101, /stagingPercentage/], ["killSwitch", "true", /killSwitch/], ["killSwitch", 1, /killSwitch/], ["minimumSupportedVersion", "1.9", /minimumSupportedVersion/], ["forceInstallBelow", "v1.0.0", /forceInstallBelow/], ["fullInstallVersionGap", -1, /fullInstallVersionGap/], ["fullInstallOnMajorChange", "yes", /fullInstallOnMajorChange/], ["defaultChannel", "stable", /defaultChannel/], ["schemaVersion", 2, /schemaVersion/], ]) { test(`rejects ${field}=${JSON.stringify(value)} instead of publishing a silently permissive policy`, () => { const errors = validateUpdatePolicyDocument({ ...committed, [field]: value }); assert.equal(errors.length, 1, errors.join("\n")); assert.match(errors[0], pattern); assert.throws(() => assertValidUpdatePolicy(JSON.stringify({ ...committed, [field]: value })), /refusing to publish/); }); } test("rejects missing safety fields, unknown fields and malformed channels", () => { const { killSwitch: _omit, ...withoutKillSwitch } = committed; assert.match(validateUpdatePolicyDocument(withoutKillSwitch).join("\n"), /killSwitch/); assert.match(validateUpdatePolicyDocument({ ...committed, killswitch: true }).join("\n"), /unknown field "killswitch"/); assert.match( validateUpdatePolicyDocument({ ...committed, channels: { ...committed.channels, beta: { allowPrerelease: "true" } } }).join("\n"), /channels\.beta/, ); assert.match( validateUpdatePolicyDocument({ ...committed, channels: { ...committed.channels, rogue: { allowPrerelease: true } } }).join("\n"), /unknown channel "rogue"/, ); }); test("rejects non-object and non-JSON input", () => { assert.deepEqual(validateUpdatePolicyDocument([]), ["update-policy.json must be a JSON object"]); assert.throws(() => assertValidUpdatePolicy("{"), /not valid JSON/); assert.throws(() => assertValidUpdatePolicy(Buffer.from("null")), /must be a JSON object/); });