mirror of
https://github.com/morluto/rea
synced 2026-10-27 22:45:19 -04:00
fix(evidence): own cached snapshot data
This commit is contained in:
@@ -33,6 +33,66 @@ import {
|
||||
import { EvidenceLedger } from "../investigation/EvidenceLedger.js";
|
||||
import { enhancedOutputSchemas } from "../../contracts/toolOutputSchemaGroups.js";
|
||||
|
||||
it.each(["provider", "workflow"] as const)(
|
||||
"owns nested %s execution data before returning control to callers",
|
||||
(kind) => {
|
||||
const cache = new AnalysisSnapshotCache();
|
||||
const target = structuredClone(ANALYSIS_SNAPSHOT_TARGET);
|
||||
const profile = structuredClone(ANALYSIS_SNAPSHOT_PROFILE);
|
||||
const analysisProfile =
|
||||
kind === "provider" ? profile : workflowAnalysisProfile(profile);
|
||||
const execution = createAnalysisExecution(
|
||||
{ nested: { value: "original" } },
|
||||
structuredClone(
|
||||
kind === "provider"
|
||||
? ANALYSIS_SNAPSHOT_PROVIDER
|
||||
: REA_WORKFLOW_PROVIDER,
|
||||
),
|
||||
{
|
||||
rawResult: { nested: { value: "raw" } },
|
||||
subject: target,
|
||||
analysisProfile,
|
||||
locations: [{ kind: "address", address: "0x1000" }],
|
||||
relationshipCoverage: {
|
||||
status: "partial",
|
||||
limitations: ["original coverage"],
|
||||
},
|
||||
},
|
||||
);
|
||||
const input = {
|
||||
target,
|
||||
profile,
|
||||
operation: "procedure_info" as const,
|
||||
parameters: { address: "0x1000", document: "fixture" },
|
||||
execution: { ...execution, analysisProfile },
|
||||
};
|
||||
if (kind === "provider") cache.record(input);
|
||||
else cache.recordWorkflow(input);
|
||||
const entries = () =>
|
||||
kind === "provider" ? cache.entries() : cache.workflowEntries();
|
||||
const expected = entries();
|
||||
for (const payload of [execution.result, execution.rawResult]) {
|
||||
if (payload === null || typeof payload !== "object")
|
||||
throw new Error("Expected structured observation payload");
|
||||
Reflect.set(payload, "nested", { value: "caller edit" });
|
||||
}
|
||||
const location = execution.locations[0];
|
||||
if (location !== undefined) Reflect.set(location, "address", "0x2000");
|
||||
if (execution.relationshipCoverage?.status === "partial")
|
||||
execution.relationshipCoverage.limitations.push("caller edit");
|
||||
Reflect.set(execution.limitations, 0, "caller limitation");
|
||||
Reflect.set(execution.provider, "name", "caller provider");
|
||||
Reflect.set(execution.subject, "path", "/tmp/caller-edited-subject");
|
||||
if (kind === "workflow") {
|
||||
const upstream = analysisProfile.parameters.upstream_analysis_profile;
|
||||
if (upstream === null || typeof upstream !== "object")
|
||||
throw new Error("Expected nested workflow profile");
|
||||
Reflect.set(upstream, "parameters", { loader: "caller profile" });
|
||||
}
|
||||
expect(entries()).toEqual(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it("exports independent nested query, workflow and Evidence payloads", () => {
|
||||
const cache = new AnalysisSnapshotCache();
|
||||
const target = ANALYSIS_SNAPSHOT_TARGET;
|
||||
|
||||
@@ -358,25 +358,26 @@ type SnapshotExecutionProjection = Pick<
|
||||
| "subject"
|
||||
>;
|
||||
|
||||
/** Project one authenticated execution into the shared persisted snapshot shape. */
|
||||
/** Own one execution's snapshot data independently of its caller-visible result. */
|
||||
const snapshotExecutionProjection = (
|
||||
execution: SnapshotExecution,
|
||||
provider: AnalysisSnapshotEntry["execution"]["provider"],
|
||||
): SnapshotExecutionProjection => ({
|
||||
result: execution.result,
|
||||
raw_result: execution.rawResult,
|
||||
provider,
|
||||
limitations: [...execution.limitations],
|
||||
relationship_coverage: execution.relationshipCoverage ?? null,
|
||||
locations: [...execution.locations],
|
||||
subject:
|
||||
execution.subject === null
|
||||
? null
|
||||
: subjectSchema.parse({
|
||||
...execution.subject,
|
||||
architecture: execution.subject.architecture ?? null,
|
||||
}),
|
||||
});
|
||||
): SnapshotExecutionProjection =>
|
||||
entrySchema.shape.execution.parse({
|
||||
result: execution.result,
|
||||
raw_result: execution.rawResult,
|
||||
provider,
|
||||
limitations: execution.limitations,
|
||||
relationship_coverage: execution.relationshipCoverage ?? null,
|
||||
locations: execution.locations,
|
||||
subject:
|
||||
execution.subject === null
|
||||
? null
|
||||
: {
|
||||
...execution.subject,
|
||||
architecture: execution.subject.architecture ?? null,
|
||||
},
|
||||
});
|
||||
|
||||
const canonicalJson = (value: unknown): string => {
|
||||
const json = jsonValueSchema.parse(value);
|
||||
@@ -549,7 +550,7 @@ export const createAnalysisSnapshotWorkflowEntry = (input: {
|
||||
execution,
|
||||
execution.analysisProfile.provider,
|
||||
),
|
||||
analysis_profile: execution.analysisProfile,
|
||||
analysis_profile: analysisProfileSchema.parse(execution.analysisProfile),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,6 +14,59 @@ import { buildManagedPeFixture } from "../../../src/dotnet/ManagedPe.fixture.js"
|
||||
import { createTestBinarySession } from "../../fixtures/binarySession.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
it("keeps real provider replay and persisted Evidence independent of caller edits", async () => {
|
||||
const directory = await createTestTempDirectory(
|
||||
"rea-snapshot-result-ownership-",
|
||||
);
|
||||
const path = join(directory, "application.exe");
|
||||
await writeFile(path, buildManagedPeFixture());
|
||||
const provider = new ManagedStaticProvider();
|
||||
const profile = createAnalysisProfile(MANAGED_STATIC_PROVIDER, {
|
||||
fixture: "snapshot-result-ownership",
|
||||
});
|
||||
const session = createTestBinarySession(provider, {
|
||||
resolveAnalysisProfile: () => Promise.resolve(ok({ profile })),
|
||||
});
|
||||
onTestFinished(async () => {
|
||||
const closed = await session.close();
|
||||
if (!closed.ok) throw closed.error;
|
||||
});
|
||||
const opened = await session.open(path);
|
||||
if (!opened.ok) throw opened.error;
|
||||
const observed = await session.execute("inspect_managed_artifact", {});
|
||||
if (!observed.ok) throw observed.error;
|
||||
const expected = structuredClone(observed.value.result);
|
||||
if (observed.value.evidenceId === undefined)
|
||||
throw new Error("Real managed observation has no Evidence identity");
|
||||
const historical = session.evidenceById(observed.value.evidenceId);
|
||||
if (historical === undefined) throw new Error("Observation was not retained");
|
||||
if (
|
||||
observed.value.result === null ||
|
||||
typeof observed.value.result !== "object"
|
||||
)
|
||||
throw new Error("Expected a structured managed artifact result");
|
||||
Reflect.set(observed.value.result, "caller_edit", "must not enter replay");
|
||||
|
||||
const replayed = await session.execute("inspect_managed_artifact", {});
|
||||
if (!replayed.ok) throw replayed.error;
|
||||
expect(replayed.value.evidenceId).toBe(observed.value.evidenceId);
|
||||
expect(replayed.value.result).toEqual(expected);
|
||||
expect(session.evidenceById(observed.value.evidenceId)).toEqual(historical);
|
||||
const snapshot = session.exportAnalysisSnapshot();
|
||||
if (!snapshot.ok) throw snapshot.error;
|
||||
const snapshotPath = join(directory, "analysis.json");
|
||||
const written = await session.writeAnalysisSnapshot(
|
||||
snapshot.value,
|
||||
snapshotPath,
|
||||
false,
|
||||
);
|
||||
if (!written.ok) throw written.error;
|
||||
const restored = await readAnalysisSnapshot(snapshotPath);
|
||||
if (!restored.ok) throw restored.error;
|
||||
expect(restored.value.entries[0]?.execution.result).toEqual(expected);
|
||||
expect(restored.value.evidence_bundle.records).toContainEqual(historical);
|
||||
});
|
||||
|
||||
it("reruns ambiguous imported observations without changing their historical Evidence", async () => {
|
||||
const directory = await createTestTempDirectory("rea-snapshot-provenance-");
|
||||
const path = join(directory, "application.exe");
|
||||
|
||||
Reference in New Issue
Block a user