build(desktop): allow controlled unsigned v0.1.0 release
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
This commit is contained in:
@@ -2,9 +2,12 @@ import { access, readFile } from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
import { basename, 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 desktopReleasePolicy = await loadDesktopReleasePolicy();
|
||||
const desktopReleaseResolution = resolveDesktopReleasePolicy(packageInfo.version, desktopReleasePolicy);
|
||||
const failures = [];
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
@@ -21,6 +24,11 @@ const feedPath = resolve(
|
||||
);
|
||||
const artifactDir = optionValue("--artifacts-dir") || process.env.DESKTOP_UPDATE_ARTIFACTS_DIR;
|
||||
const expectedBaseUrl = optionValue("--base-url") || process.env.DESKTOP_UPDATE_BASE_URL;
|
||||
const requiresProvenance = args.includes("--require-provenance");
|
||||
const provenancePath =
|
||||
optionValue("--provenance") ||
|
||||
process.env.DESKTOP_RELEASE_PROVENANCE ||
|
||||
(artifactDir ? resolve(artifactDir, "DESKTOP-RELEASE-PROVENANCE.json") : undefined);
|
||||
const requiredPlatforms = new Set([
|
||||
"darwin-aarch64",
|
||||
"darwin-x86_64",
|
||||
@@ -94,6 +102,56 @@ const assertManifestEntries = async (checksums) => {
|
||||
}
|
||||
};
|
||||
|
||||
const verifyProvenance = async (checksums) => {
|
||||
if (!requiresProvenance) return;
|
||||
if (!provenancePath) {
|
||||
fail("Desktop release provenance path is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
let provenance;
|
||||
try {
|
||||
provenance = JSON.parse(await readFile(provenancePath, "utf8"));
|
||||
} catch (error) {
|
||||
fail(`Cannot read desktop release provenance ${provenancePath}: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(provenance.schemaVersion === 1, "Desktop release provenance schemaVersion must be 1.");
|
||||
assert(provenance.version === packageInfo.version, "Desktop release provenance version must match the package version.");
|
||||
assert(provenance.tag === `v${packageInfo.version}`, "Desktop release provenance tag must match the package version.");
|
||||
assert(/^[0-9a-f]{40}$/i.test(provenance.commit || ""), "Desktop release provenance must contain a full commit SHA.");
|
||||
assert(
|
||||
provenance.platformSigningMode === desktopReleaseResolution.platformSigningMode,
|
||||
`Desktop release provenance platformSigningMode must be ${desktopReleaseResolution.platformSigningMode}.`,
|
||||
);
|
||||
assert(
|
||||
provenance.platformSigning?.macos === desktopReleaseResolution.macosSigning,
|
||||
`Desktop release provenance macOS signing must be ${desktopReleaseResolution.macosSigning}.`,
|
||||
);
|
||||
assert(
|
||||
provenance.platformSigning?.windows === desktopReleaseResolution.windowsSigning,
|
||||
`Desktop release provenance Windows signing must be ${desktopReleaseResolution.windowsSigning}.`,
|
||||
);
|
||||
assert(
|
||||
provenance.updaterSigning === "required-and-verified",
|
||||
"Desktop release provenance must record required-and-verified updater signing.",
|
||||
);
|
||||
assert(
|
||||
provenance.artifactLabel === desktopReleaseResolution.artifactLabel,
|
||||
`Desktop release provenance artifactLabel must be ${desktopReleaseResolution.artifactLabel}.`,
|
||||
);
|
||||
if (desktopReleaseResolution.warningRequired) {
|
||||
assert(
|
||||
Array.isArray(provenance.warnings) && provenance.warnings.length >= 2,
|
||||
"Unsigned platform release provenance must include installation trust warnings.",
|
||||
);
|
||||
}
|
||||
if (artifactDir) {
|
||||
await assertChecksum(checksums, provenancePath, "desktop release provenance");
|
||||
}
|
||||
};
|
||||
|
||||
let feed;
|
||||
try {
|
||||
feed = JSON.parse(await readFile(feedPath, "utf8"));
|
||||
@@ -104,6 +162,7 @@ try {
|
||||
if (feed) {
|
||||
const checksums = await readChecksumManifest();
|
||||
await assertManifestEntries(checksums);
|
||||
await verifyProvenance(checksums);
|
||||
const normalizedFeedVersion = String(feed.version || "").replace(/^v/, "");
|
||||
const platforms = feed.platforms || {};
|
||||
const darwinArm = platforms["darwin-aarch64"];
|
||||
|
||||
Reference in New Issue
Block a user