Files
reverse-engineering-anything/src/application/javascript/JavaScriptApplicationEvidence.ts
T
c4aaf813e0 fix(javascript): retain selected application paths in Evidence
Record the admitted selected path separately from canonical artifact identity in successful and partial Evidence. Anchor relative inputs consistently across both CLI routes using the existing caller-path owner.

Adapt shared client verifier assertions and boundary coverage from PR #5261, and the dedicated-route anchoring correction proposed in PR #5265. Historical parsing remains independent of live paths, including legacy records without the parameter.

Validation: 118 focused tests in eight files, static and docs checks, discovery, and installed Gemini CLI 0.29.5 loopback verification of 207 schemas/241 examples passed. Synthetic static-analysis fixtures; no live Google API or native target execution.

Fixes #5258

Co-authored-by: kwakhyun <khyun2348@naver.com>
Co-authored-by: vishal-tambi <tambivishal3@gmail.com>
2026-10-20 00:37:45 +08:00

117 lines
4.0 KiB
TypeScript

import {
createImmutableEvidenceSteps,
type Evidence,
type EvidenceObservation,
} from "../../domain/evidence.js";
import type {
AnalyzeJavaScriptApplicationInput,
JavaScriptApplicationAnalysisResult,
} from "../../domain/javascript/javascriptApplicationAnalysis.js";
import { JAVASCRIPT_APPLICATION_PROVIDER } from "../InvestigationProviders.js";
import { freezeOwnedJsonSnapshotSteps } from "../../domain/immutableJson.js";
import { rememberOwnedApplicationGraphEvidence } from "./JavaScriptApplicationEvidenceGraph.js";
import { completeJavaScriptAnalysisSteps } from "./JavaScriptAnalysisControl.js";
import { jsonValueValidationSteps } from "../../domain/jsonValue.js";
import type { ProgressReporter } from "../ProgressReporter.js";
/** Create owned analysis Evidence while allowing request cancellation during sealing and hashing. */
export const createOwnedJavaScriptApplicationEvidenceCooperatively = async (
input: AnalyzeJavaScriptApplicationInput,
result: JavaScriptApplicationAnalysisResult,
signal?: AbortSignal,
progress?: ProgressReporter,
): Promise<Evidence> => {
await reportEvidencePhase(
progress,
"seal_javascript_application_result",
"Sealing the complete application analysis result",
);
const snapshot = await completeJavaScriptAnalysisSteps(
freezeOwnedJsonSnapshotSteps(result),
signal,
);
await reportEvidencePhase(
progress,
"validate_javascript_application_evidence",
"Validating the immutable application Evidence JSON",
);
// The Evidence envelope consumes the completed immutable validation cache.
await completeJavaScriptAnalysisSteps(
jsonValueValidationSteps(snapshot),
signal,
);
await reportEvidencePhase(
progress,
"hash_javascript_application_evidence",
"Hashing the complete application analysis Evidence",
);
const evidence = await completeJavaScriptAnalysisSteps(
createImmutableEvidenceSteps(
applicationSubject(snapshot),
JAVASCRIPT_APPLICATION_PROVIDER,
applicationObservation(input, snapshot),
),
signal,
);
return rememberOwnedApplicationGraphEvidence(evidence, snapshot);
};
const reportEvidencePhase = (
progress: ProgressReporter | undefined,
phase: string,
message: string,
): Promise<void> =>
progress?.report({ phase, completed: 0, total: 1, message }) ??
Promise.resolve();
const applicationSubject = (result: JavaScriptApplicationAnalysisResult) => ({
path: result.input_path,
sha256: result.root_artifact_sha256,
format: result.format,
});
const applicationObservation = (
input: AnalyzeJavaScriptApplicationInput,
result: JavaScriptApplicationAnalysisResult,
): EvidenceObservation => ({
predicateType: "rea.javascript-application-analysis",
operation: "analyze_javascript_application",
parameters: parameters(input),
result,
rawResult: null,
confidence: "derived",
authority: "shipped-artifact",
environment: null,
limitations: result.limitations,
locations: [{ kind: "artifact-path", path: "artifact-root" }],
});
const parameters = (
input: AnalyzeJavaScriptApplicationInput,
): EvidenceObservation["parameters"] => ({
input_path: input.input_path,
format: input.format,
integrity_policy: input.integrity_policy,
...(input.max_semantic_nodes === undefined
? {}
: { max_semantic_nodes: input.max_semantic_nodes }),
...(input.max_semantic_nodes_per_file === undefined
? {}
: { max_semantic_nodes_per_file: input.max_semantic_nodes_per_file }),
...(input.max_semantic_unknowns === undefined
? {}
: { max_semantic_unknowns: input.max_semantic_unknowns }),
...(input.max_semantic_unknowns_per_file === undefined
? {}
: { max_semantic_unknowns_per_file: input.max_semantic_unknowns_per_file }),
...(input.source_paths === undefined
? {}
: { source_paths: input.source_paths }),
...(input.max_heap_mb === undefined
? {}
: { max_heap_mb: input.max_heap_mb }),
...(input.analysis_timeout_ms === undefined
? {}
: { analysis_timeout_ms: input.analysis_timeout_ms }),
});