Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ci/source-shape-test-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@
"test": "restore helper re-asserts 2770/660 after the tree is tightened to 700/600",
"category": "security"
},
{
"file": "test/install/installer-homebrew-formula-reuse-trust.test.ts",
"test": "accepts the prospective dev MUSL sandbox template with its trusted digest",
"category": "security"
},
{
"file": "test/mcp/mcp-tool-discovery-image-contract.test.ts",
"test": "pins the reviewed image runtime artifacts exactly",
Expand Down
23 changes: 19 additions & 4 deletions scripts/checks/extract-installer-pins.mts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ const MAX_INSTALLER_INPUT_BYTES = 1024 * 1024;
// Each release record is one base-trusted qualification unit. The parser
// selects one record before it accepts candidate release data or emits the
// manifest and formula identities consumed by the shell checker.
// The development-channel MUSL selector changes the version-independent
// operational template. Its exact prospective digests are repeated only for
// release records that can select that same template; dependent installer
// hash tests execute the corresponding release and qualification fixtures.
const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
{
brevTemplateSha256: ["c0a4ddf25a02a9fe02b2df53a60942ea887610f04d4ce16a121b6e79a5aeff1a"],
Expand All @@ -92,6 +96,7 @@ const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
installerTemplateSha256: [
"6226811887cc5c1a721a96fbf062f5ce5f75b09d3a8a1de49ed4dadc3236eb0c",
"c3418c0837c450df89ca1b6ca3a598cdee47b0d30e2c2433fd7732ec35c2ccc2",
"ec5d942bf1b1af45ffbdb2c1ceeb8ede25a0169d9f856ad3a83577d81088ee37",
],
manifests: [
{
Expand Down Expand Up @@ -135,6 +140,7 @@ const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
installerTemplateSha256: [
"6226811887cc5c1a721a96fbf062f5ce5f75b09d3a8a1de49ed4dadc3236eb0c",
"c3418c0837c450df89ca1b6ca3a598cdee47b0d30e2c2433fd7732ec35c2ccc2",
"ec5d942bf1b1af45ffbdb2c1ceeb8ede25a0169d9f856ad3a83577d81088ee37",
],
manifests: [
{
Expand Down Expand Up @@ -173,6 +179,7 @@ const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
installerTemplateSha256: [
"6226811887cc5c1a721a96fbf062f5ce5f75b09d3a8a1de49ed4dadc3236eb0c",
"c3418c0837c450df89ca1b6ca3a598cdee47b0d30e2c2433fd7732ec35c2ccc2",
"ec5d942bf1b1af45ffbdb2c1ceeb8ede25a0169d9f856ad3a83577d81088ee37",
],
manifests: [
{
Expand Down Expand Up @@ -202,6 +209,7 @@ const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
installerTemplateSha256: [
"6226811887cc5c1a721a96fbf062f5ce5f75b09d3a8a1de49ed4dadc3236eb0c",
"c3418c0837c450df89ca1b6ca3a598cdee47b0d30e2c2433fd7732ec35c2ccc2",
"ec5d942bf1b1af45ffbdb2c1ceeb8ede25a0169d9f856ad3a83577d81088ee37",
],
manifests: [
{
Expand Down Expand Up @@ -247,6 +255,8 @@ const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
"d3ee11fd805d84c0e0f760831e091c1f16632e61cf9c1af7e7856e0aafc9de54",
"c3418c0837c450df89ca1b6ca3a598cdee47b0d30e2c2433fd7732ec35c2ccc2",
"741febd02f3a6b18c8aa5e34e42e23a200c8a4b09b41a7c0de045bf65b0a9bdd",
"ec5d942bf1b1af45ffbdb2c1ceeb8ede25a0169d9f856ad3a83577d81088ee37",
"69e7f5d873765164cfd7aa6bd97ab38d15fb8e6009e9943d8b8b6aa7fd9a100a",
],
manifests: [
{
Expand Down Expand Up @@ -290,6 +300,7 @@ const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
installerTemplateSha256: [
"6226811887cc5c1a721a96fbf062f5ce5f75b09d3a8a1de49ed4dadc3236eb0c",
"c3418c0837c450df89ca1b6ca3a598cdee47b0d30e2c2433fd7732ec35c2ccc2",
"ec5d942bf1b1af45ffbdb2c1ceeb8ede25a0169d9f856ad3a83577d81088ee37",
],
manifests: [
{
Expand Down Expand Up @@ -336,16 +347,20 @@ const TRUSTED_OPENSHELL_RELEASES: readonly OpenShellReleaseTrust[] = [
// The first template came from the downstream 0.0.106 pin. The second authorizes its
// fail-before-download strings preflight. The third authorizes repair when an existing formula
// has an invalid checksum or its release formula is unavailable. The fourth preserves that
// template after installer tests moved under test/install. Homebrew owns the formula source
// state, so NemoClaw cannot correct it there; the installer verifies the trusted release
// formula before reuse. installer-homebrew-formula-reuse-trust.test.ts and
// installer-hash-check.test.ts lock the template and trust transitions. Remove the repair
// template after installer tests moved under test/install. Per the intentional two-step trust
// rollout in check-installer-hash.sh, the fifth authorizes the exact tested follow-up template
// before that installer can select the MUSL development sandbox while preserving stable GNU.
// Homebrew owns the formula source state, so NemoClaw cannot correct it there; the installer
// verifies the trusted release formula before reuse. installer-homebrew-formula-reuse-trust.test.ts
// and installer-hash-check.test.ts lock the template and trust transitions. Remove the repair
// digests when supported Homebrew installs no longer need this repair path.
installerTemplateSha256: [
"5d4cdb2db60df7539193b486ac15bb9be96ec1d40fc0f739a94d4d2f0bf597a0",
"e850e927aab619d52c5de72967137569d65dd7fa669920c7c5b558f0770140d1",
"e7d51536442b217e3d5e77c4ba3b7c25e6a74898bf22523f7fb58627d34329cb",
"18175cf47a0fece8ce75e5d523185062c7a7c913a3f4ceafbba4a7ca4df7c69b",
"293f45ea1d54e1531c3a070123c04b47f972f29504bd8902a44ab71acdfe6cca",
"ee3db19d06d34a625bff9e0ab021f095ce97eadf5f7a98fc60def62af87577ad",
],
manifests: [
{
Expand Down
2 changes: 1 addition & 1 deletion test/install/installer-hash-check.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@ INSTALLER_MUTATIONS["reviewed-release-cohorts-url-drift"] = (source) =>
"https://github.com/NVIDIA/OpenShell/releases/download/${RELEASE_TAG}/$name",
"https://attacker.invalid/openshell/${RELEASE_TAG}/$name",
);

for (const mode of [
"complete-multiple-installer-versions",
"secondary-installer-version-mismatch",
Expand Down Expand Up @@ -537,6 +536,7 @@ const trustAlternateRelease = (source: string): string => {
},
installerTemplateSha256: [
"c3418c0837c450df89ca1b6ca3a598cdee47b0d30e2c2433fd7732ec35c2ccc2",
"ec5d942bf1b1af45ffbdb2c1ceeb8ede25a0169d9f856ad3a83577d81088ee37",
],
manifests: [
${manifests}
Expand Down
73 changes: 61 additions & 12 deletions test/install/installer-homebrew-formula-reuse-trust.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const TRUSTED_V00106_TEMPLATE_DIGESTS = [
"e850e927aab619d52c5de72967137569d65dd7fa669920c7c5b558f0770140d1",
"e7d51536442b217e3d5e77c4ba3b7c25e6a74898bf22523f7fb58627d34329cb",
"18175cf47a0fece8ce75e5d523185062c7a7c913a3f4ceafbba4a7ca4df7c69b",
"293f45ea1d54e1531c3a070123c04b47f972f29504bd8902a44ab71acdfe6cca",
"ee3db19d06d34a625bff9e0ab021f095ce97eadf5f7a98fc60def62af87577ad",
] as const;
const tempDirs: string[] = [];

Expand Down Expand Up @@ -67,6 +69,36 @@ function restoreFlatInstallTestPaths(source: string): string {
);
}

function selectDevMuslSandboxTemplate(source: string): string {
const grouped = ` case "$ARCH_LABEL" in
x86_64)
ASSETS+=("openshell-gateway-x86_64-unknown-linux-gnu.tar.gz")
ASSETS+=("openshell-sandbox-x86_64-unknown-linux-gnu.tar.gz")
;;
aarch64)
ASSETS+=("openshell-gateway-aarch64-unknown-linux-gnu.tar.gz")
ASSETS+=("openshell-sandbox-aarch64-unknown-linux-gnu.tar.gz")
;;
esac`;
const devMusl = ` SANDBOX_LIBC="gnu"
if [ "$RESOLVED_CHANNEL" = "dev" ]; then
SANDBOX_LIBC="musl"
fi
case "$ARCH_LABEL" in
x86_64)
ASSETS+=("openshell-gateway-x86_64-unknown-linux-gnu.tar.gz")
ASSETS+=("openshell-sandbox-x86_64-unknown-linux-\${SANDBOX_LIBC}.tar.gz")
;;
aarch64)
ASSETS+=("openshell-gateway-aarch64-unknown-linux-gnu.tar.gz")
ASSETS+=("openshell-sandbox-aarch64-unknown-linux-\${SANDBOX_LIBC}.tar.gz")
;;
esac`;
const selected = source.replace(grouped, devMusl);
expect(selected, "grouped GNU sandbox asset selection").not.toBe(source);
return selected;
}

function runTrustCheck(source: string) {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-homebrew-reuse-trust-"));
const installer = path.join(tempDir, "install-openshell.sh");
Expand All @@ -92,6 +124,22 @@ function runTrustCheck(source: string) {
);
}

function expectTrustedTemplate(source: string, digest: string): void {
const result = runTrustCheck(source);

expect(result.status, result.stderr).toBe(0);
const records = JSON.parse(result.stdout) as Array<{
operationalTemplateSha256: string;
source: string;
}>;
const installerTemplateDigests = new Set(
records
.filter((record) => record.source === "installer")
.map((record) => record.operationalTemplateSha256),
);
expect(installerTemplateDigests).toEqual(new Set([digest]));
}

describe("installer Homebrew formula reuse trust", () => {
const previousTemplate = restoreFlatInstallTestPaths(INSTALLER_SOURCE);
const baseTemplate = removeHomebrewFormulaReuseRepair(previousTemplate);
Expand All @@ -103,19 +151,20 @@ describe("installer Homebrew formula reuse trust", () => {
] as const;

it.each(templates)("accepts the %s template with digest %s", (_label, digest, source) => {
const result = runTrustCheck(source);

expect(result.status, result.stderr).toBe(0);
const records = JSON.parse(result.stdout) as Array<{
operationalTemplateSha256: string;
source: string;
}>;
const installerTemplateDigests = new Set(
records
.filter((record) => record.source === "installer")
.map((record) => record.operationalTemplateSha256),
expectTrustedTemplate(source, digest);
});

// source-shape-contract: security -- Exact prospective installer bytes must be base-authorized before trusted CI can admit the dependent runtime change
it("accepts the prospective dev MUSL sandbox template with its trusted digest", () => {
const prospectiveTemplate = selectDevMuslSandboxTemplate(INSTALLER_SOURCE);
expect(prospectiveTemplate).toContain(
'if [ "$RESOLVED_CHANNEL" = "dev" ]; then\n SANDBOX_LIBC="musl"',
);
expectTrustedTemplate(prospectiveTemplate, TRUSTED_V00106_TEMPLATE_DIGESTS[4]);
expectTrustedTemplate(
restoreFlatInstallTestPaths(prospectiveTemplate),
TRUSTED_V00106_TEMPLATE_DIGESTS[5],
);
expect(installerTemplateDigests).toEqual(new Set([digest]));
});

it("rejects an unlisted template", () => {
Expand Down
Loading