fix(artifacts): leave .NET bundle member declarations uncompared

Upstream main compares no .NET bundle member facts. Comparing `file_type`
changed `compare_artifacts` output beyond this branch's fixes, so the kind
stays uncompared until that is decided. A changed manifest still shows as a
content change of the host.
This commit is contained in:
Entrpi committed 2026-10-30 09:46:58 +11:00
1 parent 1ffe4c08d0
commit 3e51a77607
3 files changed
+2 -86

No files matched your search

-3
View File
@@ -43,9 +43,6 @@ The host keeps its whole-file SHA-256. Each embedded file gets its expanded-byte
SHA-256, path, declared size, compressed size, and `format_metadata` declaration
(`major_version`, `minor_version`, `file_type`). Its `source_location` describes
the stored host extent, including the compressed length when applicable.
`compare_artifacts` compares each member's declared `file_type`, which tells
the host how to treat the member. The header versions come from the host's own
bytes, which content comparison covers.
The root manifest's `root_format` is `dotnet-bundle`; the root content node
still records its native PE/ELF/Mach-O format. A file-type declaration or `.dll`
suffix does not establish a valid assembly. Inspect an extracted component
+2 -5
View File
@@ -600,12 +600,9 @@ const declarationsByKind: {
type_code: metadata.type_code,
}),
},
/**
* How the manifest tells the host to treat a member. The header versions
* repeat the host's own bytes, which content comparison covers.
*/
"dotnet-bundle-entry": {
declaration: (metadata) => ({ file_type: metadata.file_type }),
notCompared:
"Its fields come from the host's bundle manifest, whose bytes the host's content comparison covers.",
},
"bun-standalone": {
notCompared:
@@ -1,78 +0,0 @@
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { dotnetBundleFixture } from "../../src/artifacts/dotnet/DotnetBundle.fixture.js";
import { artifactComparisonResultSchema } from "../../src/domain/artifactComparison.js";
import { artifactInspectionResultSchema } from "../../src/domain/artifactInspection.js";
import { artifactInventoryResultSchema } from "../../src/domain/artifactGraph.js";
import { parseEvidence, type Evidence } from "../../src/domain/evidence.js";
import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
it("compares a .NET bundle member's declared file type, not the header version", async () => {
const root = await createTestTempDirectory("rea-dotnet-comparison-");
const { call } = await connectLocalToolsMcp();
const bytes = Buffer.from("owned assembly bytes");
const inspect = async (
name: string,
fileType: number,
majorVersion?: number,
): Promise<Evidence> => {
const path = join(root, name);
await writeFile(
path,
dotnetBundleFixture([{ path: "App.dll", bytes, fileType }], majorVersion)
.bytes,
);
const opened = await call("open_binary", { path });
expect(opened.isError, JSON.stringify(opened)).not.toBe(true);
const response = await call("inspect_artifact", {});
expect(response.isError, JSON.stringify(response)).not.toBe(true);
const inventory = artifactInspectionResultSchema
.parse(parseEvidence(response.structuredContent).normalized_result)
.substeps.find(
({ operation }) => operation === "inventory_artifact",
)?.evidence;
if (inventory === undefined) throw new Error("Missing inventory Evidence");
return parseEvidence(inventory);
};
const memberChanges = async (left: Evidence, right: Evidence) => {
const response = await call("compare_artifacts", { left, right });
expect(response.isError, JSON.stringify(response)).not.toBe(true);
return artifactComparisonResultSchema
.parse(parseEvidence(response.structuredContent).normalized_result)
.changes.filter(({ logical_path }) => logical_path !== ".");
};
const member = (evidence: Evidence) => {
const occurrence = artifactInventoryResultSchema
.parse(evidence.normalized_result)
.occurrences.find(({ logical_path }) => logical_path === "App.dll");
if (occurrence === undefined) throw new Error("Missing App.dll");
return occurrence;
};
const assembly = await inspect("assembly", 1);
// File type 2 declares a native binary, so the host treats the same bytes
// another way.
const native = await inspect("native", 2);
expect(member(native)).toMatchObject({
artifact_id: member(assembly).artifact_id,
format_metadata: { kind: "dotnet-bundle-entry", file_type: 2 },
});
expect(await memberChanges(assembly, native)).toMatchObject([
{
logical_path: "App.dll",
classification: "changed",
dimensions: ["metadata"],
},
]);
// Every member repeats the header version, which the host's bytes hold.
const older = await inspect("older", 1, 2);
expect(member(older)).toMatchObject({
artifact_id: member(assembly).artifact_id,
format_metadata: { major_version: 2, file_type: 1 },
});
expect(await memberChanges(assembly, older)).toEqual([]);
});