From b9e29c52d483704c64cd88f87eaa117066288602 Mon Sep 17 00:00:00 2001 From: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Date: Fri, 9 Oct 2026 14:39:51 +0000 Subject: [PATCH] test(artifacts): pin per-occurrence roles for direct Mach-O roots and shared bytes Both reported failures were fixed by 63bf9140, which moved kind and executable facts from content nodes to occurrences, but neither reproduction had a regression test. Pin the direct-file Mach-O root kind and permission against its bundle occurrence, and the Apple JavaScript component and runtime family next to byte-identical text resources. Refs #1234 Refs #1235 Co-Authored-By: Claude Opus 5.5 --- .../ArtifactOccurrenceIdentity.test.ts | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/artifacts/inventory/ArtifactOccurrenceIdentity.test.ts b/src/artifacts/inventory/ArtifactOccurrenceIdentity.test.ts index b3c9332fe..10351f9d4 100644 --- a/src/artifacts/inventory/ArtifactOccurrenceIdentity.test.ts +++ b/src/artifacts/inventory/ArtifactOccurrenceIdentity.test.ts @@ -6,8 +6,10 @@ import { describe, expect, it } from "vitest"; import { inventoryArtifact } from "./ArtifactInventory.js"; import { compareArtifacts } from "../../domain/artifactComparison.js"; +import { projectAppleApplication } from "../../domain/apple/appleApplication.js"; import { createEvidence } from "../../domain/evidence.js"; import { jsonValueSchema } from "../../domain/jsonValue.js"; +import { thinMach } from "../../domain/binaryTarget.fixture.js"; import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js"; const names = ["main.js", "payload.bin", "addon.node"]; @@ -90,6 +92,55 @@ describe("content identity and occurrence facts", () => { ).toEqual(["."]); }); + it.each([ + ["a later", ["a.js", "z.txt"]], + ["an earlier", ["0.txt", "a.js"]], + ["no", ["a.js"]], + ] as const)( + "keeps the Apple JavaScript component with %s byte-identical text resource", + async (_label, resources) => { + const directory = await createTestTempDirectory("rea-apple-identity-"); + const path = join(directory, "fixture.zip"); + const writer = new ZipWriter(new Uint8ArrayWriter()); + await writer.add( + "Demo.app/Contents/Info.plist", + new TextReader( + 'CFBundleNameDemo', + ), + ); + for (const name of resources) + await writer.add( + `Demo.app/Contents/Resources/${name}`, + new TextReader('console.log("hello");\n'), + ); + await writeFile(path, await writer.close()); + const inventory = await inventoryArtifact(path); + const projection = projectAppleApplication({ + inventory_evidence: [ + createEvidence( + { path, sha256: inventory.manifest.root_sha256, format: "zip" }, + { + id: "rea-artifact-graph", + name: "artifact inventory", + version: "1", + }, + { + operation: "inventory_artifact", + parameters: {}, + result: jsonValueSchema.parse(inventory), + confidence: "observed", + authority: "shipped-artifact", + }, + ), + ], + }); + expect( + projection.components.javascript.map((component) => component.path), + ).toEqual(["Demo.app/Contents/Resources/a.js"]); + expect(projection.runtime_families).toEqual(["javascript"]); + }, + ); + it("keeps framework and ordinary directory roles separate for identical trees", async () => { const root = await createTestTempDirectory("rea-directory-roles-"); for (const name of ["Widget.framework", "resources"]) @@ -130,3 +181,56 @@ describe("content identity and occurrence facts", () => { expect(newFile?.executable).toBe(true); }); }); + +describe("directly selected executable formats", () => { + // A 64-bit little-endian arm64 MH_EXECUTE header. + const executable = () => { + const bytes = thinMach(0xcffaedfe, 0x0100000c); + bytes.writeUInt32LE(2, 12); + return bytes; + }; + + it.each([ + ["755", 0o755], + ["644", 0o644], + ] as const)( + "keeps a Mach-O executable kind separate from mode %s, directly and in a bundle", + async (_label, mode) => { + const root = await createTestTempDirectory("rea-direct-macho-"); + const directory = join(root, "Demo.app", "Contents", "MacOS"); + await mkdir(directory, { recursive: true }); + const path = join(directory, "demo"); + await writeFile(path, executable()); + await chmod(path, mode); + const facts = ( + inventory: Awaited>, + logicalPath: string, + ) => { + const occurrence = inventory.occurrences.find( + (item) => item.logical_path === logicalPath, + ); + const node = inventory.nodes.find( + (item) => item.artifact_id === occurrence?.artifact_id, + ); + return { + sha256: node?.sha256, + artifact_kind: occurrence?.artifact_kind, + artifact_format: occurrence?.artifact_format, + executable: occurrence?.executable, + }; + }; + const direct = facts(await inventoryArtifact(path), "."); + const embedded = facts( + await inventoryArtifact(join(root, "Demo.app")), + "Contents/MacOS/demo", + ); + expect(direct).toEqual({ + sha256: expect.stringMatching(/^[a-f0-9]{64}$/u), + artifact_kind: "executable", + artifact_format: "mach-o", + executable: mode === 0o755, + }); + expect(embedded).toEqual(direct); + }, + ); +});