From 3e51a776072dbf50bb12b183c851f748115aa8ab Mon Sep 17 00:00:00 2001 From: Entrpi Date: Fri, 30 Oct 2026 09:46:58 +1100 Subject: [PATCH] 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. --- docs/dotnet-bundles.md | 3 - src/domain/artifactFormatMetadata.ts | 7 +- .../artifactComparisonDotnetBundle.test.ts | 78 ------------------- 3 files changed, 2 insertions(+), 86 deletions(-) delete mode 100644 tests/acceptance/artifactComparisonDotnetBundle.test.ts diff --git a/docs/dotnet-bundles.md b/docs/dotnet-bundles.md index 616ab71385..121d030f0e 100644 --- a/docs/dotnet-bundles.md +++ b/docs/dotnet-bundles.md @@ -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 diff --git a/src/domain/artifactFormatMetadata.ts b/src/domain/artifactFormatMetadata.ts index 198c00d5d0..df807d21ca 100644 --- a/src/domain/artifactFormatMetadata.ts +++ b/src/domain/artifactFormatMetadata.ts @@ -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: diff --git a/tests/acceptance/artifactComparisonDotnetBundle.test.ts b/tests/acceptance/artifactComparisonDotnetBundle.test.ts deleted file mode 100644 index 3186044670..0000000000 --- a/tests/acceptance/artifactComparisonDotnetBundle.test.ts +++ /dev/null @@ -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 => { - 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([]); -});