From c9f95eaf9025dc89cf05c2efed22f559b567809b Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Thu, 22 Oct 2026 08:27:39 +0800 Subject: [PATCH] refactor(javascript): own graph Evidence envelope validation --- .../JavaScriptApplicationEvidenceGraph.ts | 45 +++++++----- .../javascriptApplicationWorkflows.test.ts | 68 +++++++++++++++++++ 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/application/javascript/JavaScriptApplicationEvidenceGraph.ts b/src/application/javascript/JavaScriptApplicationEvidenceGraph.ts index 3a42ce32e4..6c8e2e51c7 100644 --- a/src/application/javascript/JavaScriptApplicationEvidenceGraph.ts +++ b/src/application/javascript/JavaScriptApplicationEvidenceGraph.ts @@ -184,15 +184,12 @@ const staticRuntimeSource = ( evidence.normalized_result, [...path, "normalized_result"], ); - const unmatchedLink = result.evidence_links.find( - (evidenceId) => !evidence.evidence_links.includes(evidenceId), + assertResultEvidenceLinksInEnvelope( + result.evidence_links, + evidence, + path, + "Runtime reconciliation result", ); - if (unmatchedLink !== undefined) - throw invalidEvidence( - [...path, "normalized_result"], - "evidence_links", - `Runtime reconciliation result references Evidence ${unmatchedLink} outside its envelope.`, - ); const applicationLayer = result.static_layers.find( ({ role }) => role === "application", ); @@ -229,15 +226,12 @@ const managedApplicationSource = ( evidence.normalized_result, [...path, "normalized_result"], ); - const unmatchedLink = result.evidence_links.find( - (evidenceId) => !evidence.evidence_links.includes(evidenceId), + assertResultEvidenceLinksInEnvelope( + result.evidence_links, + evidence, + path, + "Managed application graph result", ); - if (unmatchedLink !== undefined) - throw invalidEvidence( - [...path, "normalized_result"], - "evidence_links", - `Managed application graph result references Evidence ${unmatchedLink} outside its envelope.`, - ); return { evidence, graph: result.graph, @@ -247,6 +241,25 @@ const managedApplicationSource = ( }; }; +const assertResultEvidenceLinksInEnvelope = ( + resultEvidenceLinks: readonly string[], + evidence: Evidence, + path: readonly (string | number)[], + resultLabel: + | "Runtime reconciliation result" + | "Managed application graph result", +): void => { + const unmatchedLink = resultEvidenceLinks.find( + (evidenceId) => !evidence.evidence_links.includes(evidenceId), + ); + if (unmatchedLink !== undefined) + throw invalidEvidence( + [...path, "normalized_result"], + "evidence_links", + `${resultLabel} references Evidence ${unmatchedLink} outside its envelope.`, + ); +}; + const assertApplicationSubject = ( evidence: Evidence, result: JavaScriptApplicationAnalysisResult, diff --git a/tests/boundary/filesystem/javascriptApplicationWorkflows.test.ts b/tests/boundary/filesystem/javascriptApplicationWorkflows.test.ts index 8393bad540..a757ec941f 100644 --- a/tests/boundary/filesystem/javascriptApplicationWorkflows.test.ts +++ b/tests/boundary/filesystem/javascriptApplicationWorkflows.test.ts @@ -32,7 +32,10 @@ import { } from "../../../src/domain/javascript/javascriptApplicationGraph.fixture.js"; import { writeVersionedJavaScriptApplicationFixtures } from "../../fixtures/javascriptArtifactApplication.js"; import { JAVASCRIPT_APPLICATION_PROVIDER } from "../../../src/application/InvestigationProviders.js"; +import { projectManagedApplicationGraphEvidence } from "../../../src/application/managed/ManagedApplicationGraphService.js"; +import { MANAGED_APPLICATION_GRAPH_EXAMPLE } from "../../../src/contracts/managed/managedWorkflowExamples.js"; import { JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE } from "../../../src/contracts/javascript/javascriptRuntimeReconciliationExample.js"; +import { managedApplicationGraphResultSchema } from "../../../src/domain/managed/managedApplicationGraph.js"; const temporary: string[] = []; @@ -320,6 +323,71 @@ describe("complete comparison projections", () => { }); }); +describe("Application graph Evidence envelopes", () => { + it.each(["runtime reconciliation", "managed application graph"] as const)( + "rejects %s result links outside the authenticated Evidence envelope", + (sourceKind) => { + const sourceResult = + sourceKind === "runtime reconciliation" + ? reconcileJavaScriptRuntimeEvidence( + JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE, + ) + : projectManagedApplicationGraphEvidence( + MANAGED_APPLICATION_GRAPH_EXAMPLE, + ); + if (!sourceResult.ok) throw sourceResult.error; + const source = sourceResult.value; + const result = + sourceKind === "runtime reconciliation" + ? javascriptRuntimeReconciliationResultSchema.parse( + source.normalized_result, + ) + : managedApplicationGraphResultSchema.parse(source.normalized_result); + const extraLink = `ev_${"f".repeat(64)}`; + const malformed = createEvidence(undefined, source.provider, { + predicateType: source.predicate_type, + operation: source.operation, + parameters: source.parameters, + result: jsonValueSchema.parse({ + ...result, + evidence_links: [...result.evidence_links, extraLink], + }), + rawResult: source.raw_result, + confidence: source.confidence, + authority: source.authority, + environment: source.environment, + limitations: source.limitations, + locations: source.locations, + evidenceLinks: source.evidence_links, + }); + const workflowInput = { + application: source, + seed: { kind: "route" as const, value: "/not-present" }, + direction: "both" as const, + }; + + expect(traceApplicationFeatureEvidence(workflowInput).ok).toBe(true); + const rejected = traceApplicationFeatureEvidence({ + ...workflowInput, + application: malformed, + }); + + expect(rejected).toMatchObject({ + ok: false, + error: { + issues: [ + { + path: ["application", "normalized_result", "evidence_links"], + reason: "invalid_value", + message: `${sourceKind === "runtime reconciliation" ? "Runtime reconciliation result" : "Managed application graph result"} references Evidence ${extraLink} outside its envelope.`, + }, + ], + }, + }); + }, + ); +}); + describe("JavaScript application workflow error diagnostics", () => { it("identifies the inconsistent Evidence subject in graph workflows", async () => { const root = await createTestTempDirectory(