Files
rea/tests/acceptance/rustDependencyViews.test.ts
T
morluto 02940796f1 fix(rust): retain parsed defaults in cached Evidence views
Borrow sealed reports only when they match the parsed facts; otherwise cache the owned normalized snapshot. Keep historical feature omissions unknown through saved bundles and repeated retained pages without changing the source Evidence.

Fixes #6689
2026-10-23 21:28:10 +08:00

406 lines
13 KiB
TypeScript

import { readFile, unlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { parseEvidence, createEvidence } from "../../src/domain/evidence.js";
import { createEvidenceBundle } from "../../src/domain/evidenceBundle.js";
import { rustBinarySchema } from "../../src/domain/rust/rustBinary.js";
import { analysisViewResultSchema } from "../../src/domain/analysisView/analysisView.js";
import { readEvidenceBundle } from "../../src/application/EvidenceBundleFiles.js";
import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
import { parseMcpToolError } from "../fixtures/mcpToolError.js";
import {
createRustImage,
rustDependencyPayload,
} from "../fixtures/rust/image.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
import { cliTest } from "../support/cli/cliFixture.js";
/** Both authenticated retention and portable imports query the same captured facts. */
const assertRetainedPages = async (
call: Awaited<ReturnType<typeof connectLocalToolsMcp>>["call"],
evidenceId: string,
exported: string,
) => {
for (const [filter, expected] of [
[
{ names: ["same"], versions: ["2"], fields: ["name", "version"] },
[{ index: 1, name: "same", version: "2" }],
],
[{ names: ["same"], indices: [0], fields: [] }, [{ index: 0 }]],
[{ names: ["same"], versions: [], fields: [] }, []],
] as const) {
const reply = await call("inspect_analysis_view", {
source: { kind: "retained-evidence", evidence_id: evidenceId },
view: { kind: "rust", collection: "packages", ...filter },
});
expect(reply.isError).not.toBe(true);
expect(
parseEvidence(reply.structuredContent).normalized_result,
).toMatchObject({ page: { rows: expected } });
}
for (const source of [
{ kind: "retained-evidence", evidence_id: evidenceId },
{ kind: "evidence-file", path: exported },
]) {
const reply = await call("inspect_analysis_view", {
source,
view: {
kind: "rust",
collection: "packages",
names: ["same"],
indices: [0, 1, 99],
offset: 1,
limit: 1,
fields: [],
},
});
expect(reply.isError, JSON.stringify(reply)).not.toBe(true);
expect(
parseEvidence(reply.structuredContent).normalized_result,
).toMatchObject({
parent_evidence_id: evidenceId,
page: { rows: [{ index: 1 }] },
coverage: {
total: 2,
examined: 1,
exhausted: true,
next_offset: null,
},
});
const edgeReply = await call("inspect_analysis_view", {
source,
view: {
kind: "rust",
collection: "edges",
from_indices: [1, 3],
to_indices: [0],
fields: ["from_index", "to_index"],
},
});
expect(edgeReply.isError).not.toBe(true);
expect(
parseEvidence(edgeReply.structuredContent).normalized_result,
).toMatchObject({
page: {
collection: "edges",
rows: [
{ index: 1, from_index: 1, to_index: 0 },
{ index: 3, from_index: 3, to_index: 0 },
],
},
});
const empty = await call("inspect_analysis_view", {
source,
view: {
kind: "rust",
collection: "packages",
names: [],
versions: ["1"],
fields: ["name"],
},
});
expect(
parseEvidence(empty.structuredContent).normalized_result,
).toMatchObject({
page: { rows: [] },
coverage: { total: 0, exhausted: true },
});
}
};
cliTest(
"queries stable Rust packages and edges through real CLI/MCP and portable Evidence",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-rust-views-");
const { call } = await connectLocalToolsMcp();
for (const format of ["elf", "pe", "macho"] as const) {
const path = join(root, `source.${format}`);
const output = join(root, `${format}-source.json`);
const payload = rustDependencyPayload({
packages: [
{
name: "same",
version: "1",
source: "crates.io",
dependencies: [2],
features: ["default"],
},
{
name: "same",
version: "2",
source: "git+https://upstream.example/repo",
dependencies: [0, 2],
},
{ name: "leaf", version: "1", source: "local" },
{
name: "app",
version: "1",
source: "local",
dependencies: [0, 1],
root: true,
},
],
});
await writeFile(path, createRustImage({ format, payload }));
const fullReply = await call("inspect_rust_binary", { path });
expect(fullReply.isError).not.toBe(true);
const full = parseEvidence(fullReply.structuredContent);
const report = rustBinarySchema.parse(full.normalized_result);
const explicit = await call("inspect_rust_binary", {
path,
detail: "complete",
});
expect(parseEvidence(explicit.structuredContent)).toEqual(full);
const selection = {
collection: "packages",
names: ["same"],
fields: ["name", "version", "dependencies", "features"],
};
const direct = await call("inspect_rust_binary", {
path,
view: selection,
});
expect(direct.isError, JSON.stringify(direct)).not.toBe(true);
const selected = parseEvidence(
direct.structuredContent,
).normalized_result;
expect(selected).toMatchObject({
kind: "rust",
parent_evidence_id: full.evidence_id,
page: {
collection: "packages",
rows: [
{
index: 0,
name: "same",
version: "1",
dependencies: [2],
features: ["default"],
},
{ index: 1, name: "same", version: "2", dependencies: [0, 2] },
],
},
});
const summary = await call("inspect_rust_binary", {
path,
detail: "summary",
});
expect(summary.isError).not.toBe(true);
expect(
parseEvidence(summary.structuredContent).normalized_result,
).toMatchObject({
kind: "summary",
summary: {
auditable_metadata: {
counts: { packages: 4, edges: 5 },
format_version: null,
},
},
source_coverage: {
embedded_records: "complete",
runtime_dependencies: "unknown",
},
});
const delivered = await cli.run({
arguments: [
"inspect-rust-binary",
path,
"--view",
JSON.stringify(selection),
"--evidence_output",
output,
"--json",
],
});
expect(delivered.exitCode, delivered.stderr).toBe(0);
expect(delivered.json).toMatchObject({
summary: { normalized_result: selected },
});
const bundle = await readEvidenceBundle(output);
if (!bundle.ok) throw bundle.error;
expect(
bundle.value.records.find(
(row) => row.evidence_id === full.evidence_id,
),
).toEqual(full);
const exported = join(root, `${format}-record.json`);
await writeFile(exported, JSON.stringify(full));
await unlink(path);
await assertRetainedPages(call, full.evidence_id, exported);
const malformed = structuredClone(report);
malformed.auditable_metadata!.dependency_edges[0]!.to_index = 999;
if (full.subject == null)
throw new Error("Missing complete Rust subject");
const invalid = createEvidence(
{
path,
sha256: report.artifact.sha256,
format: format === "macho" ? "mach-o" : format,
...(full.subject.architecture === null
? {}
: { architecture: full.subject.architecture }),
},
full.provider,
{
operation: full.operation,
parameters: full.parameters,
result: malformed,
},
);
expect(
parseMcpToolError(
await call("inspect_analysis_view", {
source: { kind: "inline", evidence: invalid },
view: { kind: "rust", collection: "edges" },
}),
).error,
).toMatchObject({ code: "invalid_request" });
}
},
60000,
);
cliTest(
"queries historical feature omissions from authenticated bundles without changing the parent",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-rust-historical-features-");
const path = join(root, "source.elf");
await writeFile(
path,
createRustImage({
format: "elf",
payload: rustDependencyPayload({
packages: [{ name: "old", version: "1", source: "local" }],
}),
}),
);
const { call } = await connectLocalToolsMcp();
const captured = await call("inspect_rust_binary", { path });
expect(captured.isError, JSON.stringify(captured.content)).not.toBe(true);
const full = parseEvidence(captured.structuredContent);
const report = rustBinarySchema.parse(full.normalized_result);
const metadata = report.auditable_metadata;
if (metadata === null) throw new Error("Expected Rust dependency metadata");
if (full.subject == null)
throw new Error("Expected Rust artifact identity");
const historical = createEvidence(
{
path,
sha256: report.artifact.sha256,
format: "elf",
...(full.subject.architecture === null
? {}
: { architecture: full.subject.architecture }),
},
full.provider,
{
operation: full.operation,
parameters: full.parameters,
result: {
...report,
auditable_metadata: {
...metadata,
packages: metadata.packages.map(
({ features: _features, ...row }) => row,
),
},
},
},
);
const bundle = join(root, "historical-bundle.json");
const record = join(root, "historical-record.json");
await writeFile(bundle, JSON.stringify(createEvidenceBundle([historical])));
await writeFile(record, JSON.stringify(historical));
await unlink(path);
const view = { kind: "rust", collection: "packages", fields: ["features"] };
for (const source of [
{ kind: "retained-evidence", evidence_id: historical.evidence_id },
{ kind: "evidence-file", path: record },
]) {
const reply = await cli.run({
arguments: [
"inspect-analysis-view",
JSON.stringify({ source, view }),
...(source.kind === "retained-evidence"
? ["--evidence-bundle", bundle]
: []),
"--json",
],
});
expect(reply.exitCode, reply.stderr + JSON.stringify(reply.json)).toBe(0);
expect(parseEvidence(reply.json).normalized_result).toMatchObject({
parent_evidence_id: historical.evidence_id,
page: { rows: [{ index: 0, features: null }] },
});
}
const imported = await call("import_evidence_bundle", { path: bundle });
expect(imported.isError, JSON.stringify(imported.content)).not.toBe(true);
for (const fields of [["features"], [], ["features"]]) {
const reply = await call("inspect_analysis_view", {
source: {
kind: "retained-evidence",
evidence_id: historical.evidence_id,
},
view: { ...view, fields },
});
expect(reply.isError, JSON.stringify(reply.content)).not.toBe(true);
expect(
parseEvidence(reply.structuredContent).normalized_result,
).toMatchObject({
parent_evidence_id: historical.evidence_id,
page: {
rows: [
fields.length === 0 ? { index: 0 } : { index: 0, features: null },
],
},
});
}
expect(JSON.parse(await readFile(record, "utf8"))).toEqual(historical);
},
);
cliTest(
"preserves unknown Rust metadata and refuses invalid compact CLI choices before reading",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-rust-view-missing-");
const path = join(root, "plain.elf");
await writeFile(
path,
createRustImage({ format: "elf", omitSection: true }),
);
const { call } = await connectLocalToolsMcp();
const summary = await call("inspect_rust_binary", {
path,
detail: "summary",
});
expect(summary.isError).not.toBe(true);
const view = analysisViewResultSchema.parse(
parseEvidence(summary.structuredContent).normalized_result,
);
expect(view).toMatchObject({
summary: { auditable_metadata: null },
source_coverage: {
embedded_records: "unknown",
runtime_dependencies: "unknown",
},
});
const missing = join(root, "never-created");
for (const args of [
["--detail", "summary"],
["--view", "{"],
["--detail", "complete", "--view", '{"collection":"packages"}'],
]) {
const refused = await cli.run({
arguments: ["inspect-rust-binary", missing, ...args, "--json"],
});
expect(refused.exitCode).toBe(1);
expect(refused.json).toMatchObject({ code: "invalid_request" });
expect(JSON.stringify(refused.json)).not.toContain("ENOENT");
}
expect((await readFile(path)).length).toBeGreaterThan(0);
},
30000,
);