Skip to content
26 changes: 17 additions & 9 deletions scripts/checks/extract-installer-pins.mts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,18 @@ const MAX_INSTALLER_INPUT_BYTES = 1024 * 1024;
// only in a prerequisite trust-anchor PR that keeps the currently selected
// release; the later pin PR may then change release data without authorizing
// any operational installer change. A mismatch reports the candidate hash.
const TRUSTED_INSTALLER_TEMPLATE_SHA256 =
"2b6a6195241d6b946fe29503d8d2d99d5b864864458f510ca129e3396248ac58";
const TRUSTED_BREV_TEMPLATE_SHA256 =
"c0a4ddf25a02a9fe02b2df53a60942ea887610f04d4ce16a121b6e79a5aeff1a";
// This transition accepts the current installer and the reviewed Homebrew
// trust change consumed by #7555 (`fix(installer): trust verified Homebrew
// formula`). After this prerequisite merges, #7555 must remove the legacy hash
// and keep only the trust-enabled installer hash before it can merge.
// Base-trusted CI must validate both the prerequisite branch and #7555.
const TRUSTED_INSTALLER_TEMPLATE_SHA256_ALLOWLIST = [
"2b6a6195241d6b946fe29503d8d2d99d5b864864458f510ca129e3396248ac58",
"30c092af249b5ab62a1232aa1d19997c125c4cf9c8cea69b6800dd6bed5a5628",
] as const;
const TRUSTED_BREV_TEMPLATE_SHA256_ALLOWLIST = [
"c0a4ddf25a02a9fe02b2df53a60942ea887610f04d4ce16a121b6e79a5aeff1a",
] as const;
const EXPECTED_INSTALLER_ASSETS = [
"openshell-x86_64-unknown-linux-musl.tar.gz",
"openshell-aarch64-unknown-linux-musl.tar.gz",
Expand Down Expand Up @@ -656,7 +664,7 @@ function assertTrustedTemplate(
source: string,
functionNames: readonly string[],
selectorPatterns: readonly RegExp[],
expectedSha256: string,
expectedSha256: readonly string[],
label: string,
): void {
const normalized = normalizeTrustedInstallerTemplate(
Expand All @@ -666,10 +674,10 @@ function assertTrustedTemplate(
label,
);
const actualSha256 = createHash("sha256").update(normalized).digest("hex");
if (actualSha256 !== expectedSha256) {
if (!expectedSha256.includes(actualSha256)) {
fail(
`${label} operational template is not base-trusted; ` +
`expected_sha256=${expectedSha256}, actual_sha256=${actualSha256}`,
`expected_sha256=[${expectedSha256.join(", ")}], actual_sha256=${actualSha256}`,
);
}
}
Expand Down Expand Up @@ -956,14 +964,14 @@ function runCli(): void {
/^MAX_VERSION="([0-9]+\.[0-9]+\.[0-9]+)"$/gm,
/^DEV_MIN_VERSION="([0-9]+\.[0-9]+\.[0-9]+)"$/gm,
],
TRUSTED_INSTALLER_TEMPLATE_SHA256,
TRUSTED_INSTALLER_TEMPLATE_SHA256_ALLOWLIST,
"installer",
);
assertTrustedTemplate(
brevInstallerSource,
["openshell_cli_pinned_sha256"],
[/^\s*stable\s*\|\s*auto\)\s*OPENSHELL_VERSION="v([0-9]+\.[0-9]+\.[0-9]+)"\s*;;\s*$/gm],
TRUSTED_BREV_TEMPLATE_SHA256,
TRUSTED_BREV_TEMPLATE_SHA256_ALLOWLIST,
"Brev launchable",
);
for (const [label, runtimeVersion] of [
Expand Down
83 changes: 83 additions & 0 deletions test/installer-hash-check.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ type FixtureMode =
| "installer-later-selector-override"
| "installer-literalized-pin-input"
| "installer-min-version-drift"
| "installer-homebrew-trust-transition"
| "installer-homebrew-trust-transition-drift"
| "installer-homebrew-trust-transition-complete-current"
| "installer-homebrew-trust-transition-complete-future"
| "installer-pin-selector-drift"
| "installer-sandbox-build-control-flow"
| "installer-sandbox-build-duplicate-digest"
Expand Down Expand Up @@ -223,6 +227,35 @@ const mutateSandboxBuildFunction = (
return `${source.slice(0, start)}${mutated}${source.slice(end)}`;
};

const applyHomebrewTrustTransition = (source: string): string => {
const marker = ` formula_ref="\${HOMEBREW_TAP}/\${HOMEBREW_FORMULA_NAME}"
if brew list --formula "$HOMEBREW_FORMULA_NAME" >/dev/null 2>&1; then`;
assert.ok(source.includes(marker), "installer Homebrew formula marker must exist");
return source.replace(
marker,
` formula_ref="\${HOMEBREW_TAP}/\${HOMEBREW_FORMULA_NAME}"
if [ "$RELEASE_TAG" != "dev" ] && brew help trust >/dev/null 2>&1; then
brew trust --formula "$formula_ref" \\
|| fail "Homebrew refused to trust the checksum-verified OpenShell formula \${formula_ref}"
fi
if brew list --formula "$HOMEBREW_FORMULA_NAME" >/dev/null 2>&1; then`,
);
};

const completeHomebrewTrustTransition = (source: string): string => {
const marker = `const TRUSTED_INSTALLER_TEMPLATE_SHA256_ALLOWLIST = [
"2b6a6195241d6b946fe29503d8d2d99d5b864864458f510ca129e3396248ac58",
"30c092af249b5ab62a1232aa1d19997c125c4cf9c8cea69b6800dd6bed5a5628",
] as const;`;
assert.ok(source.includes(marker), "Homebrew trust transition allowlist must exist");
return source.replace(
marker,
`const TRUSTED_INSTALLER_TEMPLATE_SHA256_ALLOWLIST = [
"30c092af249b5ab62a1232aa1d19997c125c4cf9c8cea69b6800dd6bed5a5628",
] as const;`,
);
};

const INSTALLER_MUTATIONS: Partial<Record<FixtureMode, (source: string) => string>> = {
"duplicate-installer-pin": (source) => {
const asset = ASSETS[0];
Expand Down Expand Up @@ -281,6 +314,13 @@ const INSTALLER_MUTATIONS: Partial<Record<FixtureMode, (source: string) => strin
source.replace('local release_tag="$1" asset="$2"', "local release_tag='$1' asset='$2'"),
"installer-min-version-drift": (source) =>
source.replace('MIN_VERSION="0.0.72"', 'MIN_VERSION="0.0.85"'),
"installer-homebrew-trust-transition": applyHomebrewTrustTransition,
"installer-homebrew-trust-transition-complete-future": applyHomebrewTrustTransition,
"installer-homebrew-trust-transition-drift": (source) =>
applyHomebrewTrustTransition(source).replace(
'brew trust --formula "$formula_ref" \\',
'brew trust --formula "$HOMEBREW_TAP" \\',
),
"installer-max-version-drift": (source) =>
source.replace('MAX_VERSION="0.0.72"', 'MAX_VERSION="0.0.85"'),
"installer-pin-selector-drift": (source) =>
Expand Down Expand Up @@ -346,6 +386,11 @@ const INSTALLER_MUTATIONS: Partial<Record<FixtureMode, (source: string) => strin
"runtime-consumers-newer-than-tables": (source) =>
source.replace('MAX_VERSION="0.0.72"', 'MAX_VERSION="0.0.85"'),
};

const TRUSTED_PARSER_MUTATIONS: Partial<Record<FixtureMode, (source: string) => string>> = {
"installer-homebrew-trust-transition-complete-current": completeHomebrewTrustTransition,
"installer-homebrew-trust-transition-complete-future": completeHomebrewTrustTransition,
};
type InputMutationContext = {
blueprint: string;
brevInstaller: string;
Expand Down Expand Up @@ -685,6 +730,11 @@ function runFixture(
path.join(REPO_ROOT, "scripts", "checks", "extract-installer-pins.mts"),
trustedParserPath,
);
const mutateTrustedParser = TRUSTED_PARSER_MUTATIONS[mode] ?? ((source: string) => source);
fs.writeFileSync(
trustedParserPath,
mutateTrustedParser(fs.readFileSync(trustedParserPath, "utf8")),
);
fs.writeFileSync(
targetChecker,
trustedChecker
Expand Down Expand Up @@ -742,6 +792,39 @@ describe("installer hash verification", () => {
expect(result.stdout).toContain("All installer hashes are current");
});

it("accepts the reviewed Homebrew trust transition", () => {
const result = runFixture("installer-homebrew-trust-transition", undefined, true);

expect(result.status, result.stdout).toBe(0);
expect(result.stdout).toContain("All installer hashes are current");
});

Comment thread
coderabbitai[bot] marked this conversation as resolved.
it("rejects drift from the reviewed Homebrew trust transition", () => {
const result = runFixture("installer-homebrew-trust-transition-drift", undefined, true);

expect(result.status).toBe(1);
expect(result.stdout).toContain("installer operational template is not base-trusted");
expect(result.stdout).not.toContain("All installer hashes are current");
});

it("models completed trust transition by rejecting the legacy installer template (#7451)", () => {
const legacy = runFixture(
"installer-homebrew-trust-transition-complete-current",
undefined,
true,
);
const trustEnabled = runFixture(
"installer-homebrew-trust-transition-complete-future",
undefined,
true,
);

expect(legacy.status).toBe(1);
expect(legacy.stdout).toContain("installer operational template is not base-trusted");
expect(trustEnabled.status, trustEnabled.stdout).toBe(0);
expect(trustEnabled.stdout).toContain("All installer hashes are current");
});

it("fails closed when the Homebrew formula digest does not match", () => {
const result = runFixture("formula-mismatch", undefined, true);

Expand Down
Loading