80 lines
3.4 KiB
JavaScript
80 lines
3.4 KiB
JavaScript
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { loadDesktopReleasePolicy, resolveDesktopReleasePolicy } from "./desktop-release-policy.mjs";
|
|
|
|
const frontendDir = fileURLToPath(new URL("../", import.meta.url));
|
|
const packageInfo = JSON.parse(await readFile(resolve(frontendDir, "package.json"), "utf8"));
|
|
const args = process.argv.slice(2);
|
|
const value = (name) => {
|
|
const index = args.indexOf(name);
|
|
return index >= 0 ? args[index + 1] : undefined;
|
|
};
|
|
|
|
const policy = await loadDesktopReleasePolicy();
|
|
const resolution = resolveDesktopReleasePolicy(packageInfo.version, policy);
|
|
const tag = value("--tag") || process.env.GITHUB_REF_NAME;
|
|
const commit = value("--commit") || process.env.GITHUB_SHA;
|
|
const macosSigning = value("--macos-signing");
|
|
const windowsSigning = value("--windows-signing");
|
|
const releaseStage = value("--stage") || "complete";
|
|
const outputPath = resolve(
|
|
frontendDir,
|
|
value("--output") || "src-tauri/target/desktop-release-feed/DESKTOP-RELEASE-PROVENANCE.json",
|
|
);
|
|
|
|
const failures = [];
|
|
const assert = (condition, message) => {
|
|
if (!condition) failures.push(message);
|
|
};
|
|
|
|
assert(tag === `v${packageInfo.version}`, `Release provenance tag must be v${packageInfo.version}.`);
|
|
assert(/^[0-9a-f]{40}$/i.test(commit || ""), "Release provenance commit must be a full 40-character SHA.");
|
|
assert(macosSigning === resolution.macosSigning, `macOS signing mode must be ${resolution.macosSigning}.`);
|
|
assert(windowsSigning === resolution.windowsSigning, `Windows signing mode must be ${resolution.windowsSigning}.`);
|
|
assert(["complete", "macos-first"].includes(releaseStage), "Release provenance stage must be complete or macos-first.");
|
|
if (releaseStage === "macos-first") {
|
|
assert(
|
|
resolution.macosLocalExactTagFallback === true && resolution.windowsDelivery === "deferred-same-tag",
|
|
`v${packageInfo.version} does not approve a staged local macOS-first release.`,
|
|
);
|
|
}
|
|
|
|
if (failures.length > 0) {
|
|
throw new Error(`Desktop release provenance creation failed:\n${failures.map((item) => ` - ${item}`).join("\n")}`);
|
|
}
|
|
|
|
const provenance = {
|
|
schemaVersion: 1,
|
|
product: "CTMS Desktop",
|
|
version: packageInfo.version,
|
|
tag,
|
|
commit,
|
|
platformSigningMode: resolution.platformSigningMode,
|
|
platformSigning: {
|
|
macos: macosSigning,
|
|
windows: windowsSigning,
|
|
},
|
|
updaterSigning: "required-and-verified",
|
|
artifactLabel: resolution.artifactLabel,
|
|
distribution: resolution.distribution,
|
|
stage: releaseStage,
|
|
platformAvailability:
|
|
releaseStage === "macos-first"
|
|
? { macos: "available", windows: "pending-same-tag" }
|
|
: { macos: "available", windows: "available" },
|
|
updaterFeedActivation:
|
|
releaseStage === "macos-first" ? "withheld-pending-combined-verification" : "combined-platform-verification-required",
|
|
warnings: resolution.warningRequired
|
|
? [
|
|
"macOS is ad-hoc signed and not Apple-notarized; Gatekeeper warnings are expected.",
|
|
"Windows is not Authenticode-signed or RFC 3161 timestamped; SmartScreen warnings are expected.",
|
|
"Verify the release tag, commit, updater signatures, and SHA256SUMS.txt through a trusted channel before installation.",
|
|
]
|
|
: [],
|
|
};
|
|
|
|
await mkdir(dirname(outputPath), { recursive: true });
|
|
await writeFile(outputPath, `${JSON.stringify(provenance, null, 2)}\n`);
|
|
console.log(`Desktop release provenance created at ${outputPath}`);
|