mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
fix(artifacts): describe observed inventory scope accurately
This commit is contained in:
@@ -68,11 +68,14 @@ byte correspondence or decode the map's original source paths.
|
||||
Artifact inventories declare `coverage.scope` (`root` or `container-entries`)
|
||||
and `coverage.status` (`complete` or `unknown`) independently of diagnostic
|
||||
wording. Comparison requires matching scopes, complete graph members and complete
|
||||
traversal coverage before concluding equality. A fully observed root without
|
||||
container children can be `unchanged`; its scope notice stays in `limitations`
|
||||
without creating a gap. Content and executable metadata changes still produce
|
||||
root deltas. Missing graph members yield `truncated`; unknown traversal coverage
|
||||
or unavailable occurrence hashes retain uncertainty. Integrity mismatches remain
|
||||
traversal coverage before concluding equality. Fully observed roots can be
|
||||
`unchanged` within root scope; their scope notice stays in `limitations` without
|
||||
creating a gap. Root-scoped equality establishes equality of the observed root
|
||||
bytes. Child-container presence and unexamined format details remain unresolved,
|
||||
including when the root format is `unknown`. Content and executable metadata
|
||||
changes still produce root deltas. Missing graph members yield `truncated`;
|
||||
unknown traversal coverage or unavailable occurrence hashes retain uncertainty.
|
||||
Integrity mismatches remain
|
||||
contradictions. Static artifact equality does not establish unchanged runtime
|
||||
behavior.
|
||||
Source-map relation deltas include the content identity of the mapped source,
|
||||
|
||||
@@ -106,6 +106,8 @@ export const inventoryCoverage = (
|
||||
};
|
||||
return {
|
||||
coverage: { scope: "root", status: "complete" },
|
||||
limitations: ["Artifact has no child container entries."],
|
||||
limitations: [
|
||||
"Inventory covers root bytes only; child container entries were not examined.",
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -174,7 +174,7 @@ cliTest(
|
||||
edge_count: 0,
|
||||
});
|
||||
expect(inventory.limitations).toEqual([
|
||||
"Artifact has no child container entries.",
|
||||
"Inventory covers root bytes only; child container entries were not examined.",
|
||||
]);
|
||||
const equal = await compare(left, right);
|
||||
expect(equal.normalized_result).toMatchObject({
|
||||
@@ -182,8 +182,8 @@ cliTest(
|
||||
summary: { unchanged: 1, unknown: 0 },
|
||||
changes: [],
|
||||
limitations: [
|
||||
"Left: Artifact has no child container entries.",
|
||||
"Right: Artifact has no child container entries.",
|
||||
"Left: Inventory covers root bytes only; child container entries were not examined.",
|
||||
"Right: Inventory covers root bytes only; child container entries were not examined.",
|
||||
],
|
||||
});
|
||||
const behavior = await call("find_changed_behavior", {
|
||||
|
||||
@@ -36,7 +36,9 @@ it("compares identical complete plist inventories across CLI and MCP and creates
|
||||
throw new Error("CLI inspection did not retain inventory Evidence");
|
||||
expect(cliInventory.normalized_result).toMatchObject({
|
||||
coverage: { scope: "root", status: "complete" },
|
||||
limitations: ["Artifact has no child container entries."],
|
||||
limitations: [
|
||||
"Inventory covers root bytes only; child container entries were not examined.",
|
||||
],
|
||||
});
|
||||
|
||||
const { call } = await connectLocalToolsMcp();
|
||||
@@ -53,7 +55,9 @@ it("compares identical complete plist inventories across CLI and MCP and creates
|
||||
throw new Error("MCP inspection did not retain inventory Evidence");
|
||||
expect(mcpInventory.normalized_result).toMatchObject({
|
||||
coverage: { scope: "root", status: "complete" },
|
||||
limitations: ["Artifact has no child container entries."],
|
||||
limitations: [
|
||||
"Inventory covers root bytes only; child container entries were not examined.",
|
||||
],
|
||||
});
|
||||
|
||||
const compared = await call("compare_artifacts", {
|
||||
|
||||
@@ -20,6 +20,11 @@ import { asarHeaderBytes } from "../../fixtures/asarHeader.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { readWithoutFifoWriter } from "../../fixtures/fifoInput.js";
|
||||
import { DEFAULT_ASAR_MAX_HEADER_BYTES } from "../../../src/config/asarHeaderAdmission.js";
|
||||
import {
|
||||
CPU,
|
||||
arArchive,
|
||||
fatImage,
|
||||
} from "../../../src/artifacts/apple/MachoImage.fixture.js";
|
||||
|
||||
it.skipIf(process.platform === "win32")(
|
||||
"rejects a FIFO artifact root without waiting for a writer",
|
||||
@@ -81,6 +86,40 @@ it("keeps unavailable container traversal distinct from observed root bytes", as
|
||||
});
|
||||
});
|
||||
|
||||
it("retains root identity without asserting absent children for an unclassified FAT archive", async () => {
|
||||
const root = await createTestTempDirectory("rea-fat-archive-root-scope-");
|
||||
const path = join(root, "libfat.a");
|
||||
const archive = arArchive();
|
||||
const bytes = fatImage([
|
||||
{ cpu: CPU.x86_64, bytes: archive },
|
||||
{ cpu: CPU.arm64, bytes: archive },
|
||||
]);
|
||||
await writeFile(path, bytes);
|
||||
|
||||
const inventory = await inventoryArtifact(path);
|
||||
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
||||
expect(inventory.manifest).toMatchObject({
|
||||
root_format: "unknown",
|
||||
root_sha256: sha256,
|
||||
node_count: 1,
|
||||
occurrence_count: 1,
|
||||
edge_count: 0,
|
||||
});
|
||||
expect(inventory.nodes).toEqual([
|
||||
expect.objectContaining({ format: "unknown", sha256, size: bytes.length }),
|
||||
]);
|
||||
expect(inventory.occurrences).toEqual([
|
||||
expect.objectContaining({
|
||||
artifact_format: "unknown",
|
||||
hash_status: "verified",
|
||||
}),
|
||||
]);
|
||||
expect(inventory.coverage).toEqual({ scope: "root", status: "complete" });
|
||||
expect(inventory.limitations).toEqual([
|
||||
"Inventory covers root bytes only; child container entries were not examined.",
|
||||
]);
|
||||
});
|
||||
|
||||
it("admits a FAT root when a valid slice header starts at the prefix boundary", async () => {
|
||||
const root = await createTestTempDirectory("rea-fat-root-header-boundary-");
|
||||
const path = join(root, "universal");
|
||||
|
||||
Reference in New Issue
Block a user