Keep digests as provenance while status follows examined deltas and unresolved coverage. Refs: #3216
106 lines
3.3 KiB
TypeScript
106 lines
3.3 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
|
|
import { expect } from "vitest";
|
|
|
|
import { createEvidence } from "../../../src/domain/evidence.js";
|
|
import { bundleComparisonResultSchema } from "../../../src/domain/bundleComparison.js";
|
|
import {
|
|
createEvidenceBundle,
|
|
serializeEvidenceBundle,
|
|
} from "../../../src/domain/evidenceBundle.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
cliTest(
|
|
"compares Evidence bundles without unexplained display-only changes",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-bundle-comparison-cli-");
|
|
const leftPath = join(root, "left.json");
|
|
const displayPath = join(root, "display.json");
|
|
const changedPath = join(root, "changed.json");
|
|
const target = {
|
|
path: join(root, "left.elf"),
|
|
sha256: "a".repeat(64),
|
|
format: "elf" as const,
|
|
architecture: "x86_64" as const,
|
|
};
|
|
const record = createEvidence(
|
|
target,
|
|
{ id: "fixture", name: "Fixture", version: "1" },
|
|
{
|
|
operation: "observe",
|
|
parameters: {},
|
|
result: { observed: true },
|
|
confidence: "observed",
|
|
authority: "shipped-artifact",
|
|
},
|
|
);
|
|
const left = createEvidenceBundle([record]);
|
|
const displayOnly = {
|
|
...left,
|
|
records: [
|
|
{
|
|
...record,
|
|
subject: {
|
|
...record.subject!,
|
|
name: "renamed.elf",
|
|
local_path: join(root, "renamed.elf"),
|
|
},
|
|
},
|
|
],
|
|
};
|
|
const different = createEvidenceBundle([
|
|
createEvidence(
|
|
target,
|
|
{ id: "fixture", name: "Fixture", version: "1" },
|
|
{
|
|
operation: "observe",
|
|
parameters: {},
|
|
result: { observed: false },
|
|
confidence: "observed",
|
|
authority: "shipped-artifact",
|
|
},
|
|
),
|
|
]);
|
|
await Promise.all([
|
|
writeFile(leftPath, serializeEvidenceBundle(left)),
|
|
writeFile(displayPath, serializeEvidenceBundle(displayOnly)),
|
|
writeFile(changedPath, serializeEvidenceBundle(different)),
|
|
]);
|
|
const compare = async (path: string) =>
|
|
cli.run({ arguments: ["compare", leftPath, path, "--json"] });
|
|
const same = await compare(leftPath);
|
|
expect(same.exitCode).toBe(0);
|
|
expect(bundleComparisonResultSchema.parse(same.json)).toMatchObject({
|
|
status: "unchanged",
|
|
changes: [],
|
|
});
|
|
const display = await compare(displayPath);
|
|
expect(display.exitCode).toBe(0);
|
|
const displayResult = bundleComparisonResultSchema.parse(display.json);
|
|
expect(displayResult).toMatchObject({ status: "unchanged", changes: [] });
|
|
expect(displayResult.left_bundle_sha256).not.toBe(
|
|
displayResult.right_bundle_sha256,
|
|
);
|
|
const differentResult = await compare(changedPath);
|
|
expect(differentResult.exitCode).toBe(0);
|
|
expect(
|
|
bundleComparisonResultSchema.parse(differentResult.json),
|
|
).toMatchObject({
|
|
status: "unknown",
|
|
summary: { unresolved: 2 },
|
|
changes: [
|
|
expect.objectContaining({
|
|
entity: "evidence",
|
|
conclusion_kind: "unresolved_branch",
|
|
}),
|
|
expect.objectContaining({
|
|
entity: "evidence",
|
|
conclusion_kind: "unresolved_branch",
|
|
}),
|
|
],
|
|
});
|
|
},
|
|
);
|