mirror of
https://github.com/morluto/rea.git
synced 2026-11-09 16:26:36 +00:00
refactor(javascript): parse runtime evidence into one verified owner
This commit is contained in:
1 parent
415145d04f
commit
006b295f1d
15 files changed
+839
-512
No files matched your search
@@ -1,14 +1,15 @@
|
||||
import { resolve } from "node:path";
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
AnalysisInputError,
|
||||
AnalysisProtocolError,
|
||||
} from "../../domain/analysisErrorCore.js";
|
||||
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
|
||||
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import type { Evidence } from "../../domain/evidence.js";
|
||||
import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js";
|
||||
import { reconcileJavaScriptRuntime } from "../../domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import {
|
||||
parseRuntimeReconciliationInput,
|
||||
reconcileJavaScriptRuntime,
|
||||
type ParsedRuntimeReconciliationInput,
|
||||
} from "../../domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import { reconcileJavaScriptRuntimeInputSchema } from "../../domain/javascript/javascriptRuntimeReconciliationSchemas.js";
|
||||
import { err, ok, type Result } from "../../domain/result.js";
|
||||
import { createJavaScriptRuntimeReconciliationEvidence } from "./JavaScriptRuntimeReconciliationEvidence.js";
|
||||
@@ -31,26 +32,30 @@ export const reconcileJavaScriptRuntimeEvidence = (
|
||||
export const reconcileJavaScriptRuntimeEvidenceValidated = (
|
||||
parsedInput: z.output<typeof reconcileJavaScriptRuntimeInputSchema>,
|
||||
): Result<Evidence, AnalysisError> => {
|
||||
let parsed: ParsedRuntimeReconciliationInput;
|
||||
try {
|
||||
const input = reconcileJavaScriptRuntimeInputSchema.parse(
|
||||
parsed = parseRuntimeReconciliationInput(
|
||||
normalizeRuntimeMappingRoots(parsedInput),
|
||||
);
|
||||
const result = reconcileJavaScriptRuntime(input);
|
||||
return ok(createJavaScriptRuntimeReconciliationEvidence(input, result));
|
||||
} catch (cause: unknown) {
|
||||
if (cause instanceof z.ZodError)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(OPERATION, cause.issues, parsedInput),
|
||||
);
|
||||
if (
|
||||
cause instanceof TypeError &&
|
||||
SAFE_RECONCILIATION_INPUT_CONSTRAINTS.has(cause.message)
|
||||
)
|
||||
return err(
|
||||
new AnalysisInputError(OPERATION, undefined, [
|
||||
{ path: [], reason: "invalid_value", message: cause.message },
|
||||
]),
|
||||
);
|
||||
return err(
|
||||
new AnalysisProtocolError(
|
||||
"JavaScript runtime reconciliation input parsing failed",
|
||||
{ cause },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = reconcileJavaScriptRuntime(parsed);
|
||||
return ok(
|
||||
createJavaScriptRuntimeReconciliationEvidence(parsed.input, result),
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
return err(
|
||||
new AnalysisProtocolError(
|
||||
"JavaScript runtime reconciliation produced an invalid result",
|
||||
@@ -83,23 +88,3 @@ const isPortableAbsolutePath = (path: string): boolean =>
|
||||
path.startsWith("/") ||
|
||||
/^[a-z]:[\\/]/iu.test(path) ||
|
||||
/^(?:\\\\|\/\/)[^\\/]+[\\/][^\\/]+(?:[\\/]|$)/u.test(path);
|
||||
|
||||
const SAFE_RECONCILIATION_INPUT_CONSTRAINTS = new Set([
|
||||
"JavaScript application Evidence subject disagrees with its result",
|
||||
"Runtime reconciliation requires inspect_web_page, inspect_electron_page, observe_javascript_runtime, or capture_electron_scenario Evidence",
|
||||
"Runtime Evidence target or declared role disagrees with its result",
|
||||
"Runtime Evidence contains an invalid builtin location",
|
||||
"Runtime Evidence target disagrees with its captured result",
|
||||
"Browser Evidence target is outside its recorded origin scope",
|
||||
"Runtime Evidence contains source without source-capture selection",
|
||||
"Active Electron Evidence application path disagrees with its configured root",
|
||||
...[
|
||||
"inspect_web_page",
|
||||
"inspect_electron_page",
|
||||
"observe_javascript_runtime",
|
||||
"capture_electron_scenario",
|
||||
].map(
|
||||
(operation) =>
|
||||
`Evidence does not match the supported ${operation} contract`,
|
||||
),
|
||||
]);
|
||||
@@ -1,13 +1,21 @@
|
||||
import { createEvidence } from "../../domain/evidence.js";
|
||||
import { reconcileJavaScriptRuntime } from "../../domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import {
|
||||
parseRuntimeReconciliationInput,
|
||||
reconcileJavaScriptRuntime,
|
||||
} from "../../domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import {
|
||||
JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE,
|
||||
JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE,
|
||||
} from "./javascriptRuntimeReconciliationExample.js";
|
||||
import { createHistoricalSourceGraph } from "../../domain/referenceSourceGraph.js";
|
||||
import { reconcileJavaScriptRuntimeInputSchema } from "../../domain/javascript/javascriptRuntimeReconciliationSchemas.js";
|
||||
|
||||
const reconciliation = reconcileJavaScriptRuntime(
|
||||
JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE,
|
||||
parseRuntimeReconciliationInput(
|
||||
reconcileJavaScriptRuntimeInputSchema.parse(
|
||||
JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE,
|
||||
),
|
||||
),
|
||||
);
|
||||
const reconciliationEvidence = createEvidence(
|
||||
undefined,
|
||||
|
||||
@@ -2,22 +2,42 @@ import { classifyStaticLoadStates } from "./javascriptRuntimeLoadState.js";
|
||||
import { buildReconciledApplicationGraph } from "./javascriptRuntimeReconciliationGraph.js";
|
||||
import { reconcileRuntimeEntities } from "./javascriptRuntimeReconciliationMatching.js";
|
||||
import {
|
||||
parseRuntimeCaptures,
|
||||
parseStaticLayers,
|
||||
type ParsedStaticLayer,
|
||||
} from "./javascriptRuntimeReconciliationParsing.js";
|
||||
import {
|
||||
parseRuntimeCaptures,
|
||||
type ParsedRuntimeCapture,
|
||||
} from "./javascriptRuntimeReconciliationCaptureParsing.js";
|
||||
import { createJavaScriptRuntimeReconciliationResult } from "./javascriptRuntimeReconciliationResult.js";
|
||||
import type { JavaScriptRuntimeReconciliationResult } from "./javascriptRuntimeReconciliationSchemas.js";
|
||||
import { reconcileJavaScriptRuntimeInputSchema } from "./javascriptRuntimeReconciliationSchemas.js";
|
||||
import type { ReconcileJavaScriptRuntimeInput } from "./javascriptRuntimeReconciliationSchemas.js";
|
||||
import { projectRuntimeCaptures } from "./javascriptRuntimeReconciliationRuntime.js";
|
||||
import { collectStaticRuntimeCandidates } from "./javascriptRuntimeStaticCandidates.js";
|
||||
|
||||
/** Verified caller input and the static and runtime facts parsed from it. */
|
||||
export interface ParsedRuntimeReconciliationInput {
|
||||
readonly input: ReconcileJavaScriptRuntimeInput;
|
||||
readonly layers: readonly ParsedStaticLayer[];
|
||||
readonly captures: readonly ParsedRuntimeCapture[];
|
||||
}
|
||||
|
||||
/** Parse caller Evidence once into the owner consumed by reconciliation. */
|
||||
export const parseRuntimeReconciliationInput = (
|
||||
input: ReconcileJavaScriptRuntimeInput,
|
||||
): ParsedRuntimeReconciliationInput => ({
|
||||
input,
|
||||
layers: parseStaticLayers(input.static_layers, ["static_layers"]),
|
||||
captures: parseRuntimeCaptures(input.runtime_observations, [
|
||||
"runtime_observations",
|
||||
]),
|
||||
});
|
||||
|
||||
/** Reconcile static JAG layers with authorized passive CDP Evidence. */
|
||||
export const reconcileJavaScriptRuntime = (
|
||||
input: unknown,
|
||||
parsed: ParsedRuntimeReconciliationInput,
|
||||
): JavaScriptRuntimeReconciliationResult => {
|
||||
const parsed = reconcileJavaScriptRuntimeInputSchema.parse(input);
|
||||
const layers = parseStaticLayers(parsed.static_layers);
|
||||
const captures = parseRuntimeCaptures(parsed.runtime_observations);
|
||||
const { layers, captures } = parsed;
|
||||
const runtime = projectRuntimeCaptures(captures);
|
||||
const candidates = collectStaticRuntimeCandidates(layers);
|
||||
const matching = reconcileRuntimeEntities({
|
||||
|
||||
@@ -3,6 +3,10 @@ import { isAbsolute } from "node:path";
|
||||
import { digestCanonicalValue } from "../canonicalDigest.js";
|
||||
import { isPathWithinRoot } from "../localPath.js";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
invalidInput,
|
||||
parseAtPath,
|
||||
} from "./javascriptRuntimeReconciliationInputValidation.js";
|
||||
|
||||
import {
|
||||
classifyBrowserCompleteness,
|
||||
@@ -13,23 +17,30 @@ import {
|
||||
type ElectronActiveObservationResult,
|
||||
} from "./electronActiveObservation.js";
|
||||
import type { Evidence } from "../evidence.js";
|
||||
import type { ParsedRuntimeCapture } from "./javascriptRuntimeReconciliationParsing.js";
|
||||
import type { ParsedRuntimeCapture } from "./javascriptRuntimeReconciliationCaptureParsing.js";
|
||||
|
||||
/** Parse active Electron Evidence as a bounded, target-only runtime capture. */
|
||||
export const parseActiveElectronCapture = (
|
||||
evidence: Evidence,
|
||||
): ParsedRuntimeCapture => {
|
||||
assertIdentity(evidence);
|
||||
const result = electronActiveObservationResultSchema.parse(
|
||||
const result = parseAtPath(
|
||||
(value) => electronActiveObservationResultSchema.parse(value),
|
||||
evidence.normalized_result,
|
||||
["normalized_result"],
|
||||
);
|
||||
const parameters = parseAtPath(
|
||||
(value) =>
|
||||
z
|
||||
.object({
|
||||
application_path: absolutePathSchema,
|
||||
application_root: absolutePathSchema,
|
||||
})
|
||||
.passthrough()
|
||||
.parse(value),
|
||||
evidence.parameters,
|
||||
["parameters"],
|
||||
);
|
||||
const parameters = z
|
||||
.object({
|
||||
application_path: absolutePathSchema,
|
||||
application_root: absolutePathSchema,
|
||||
})
|
||||
.passthrough()
|
||||
.parse(evidence.parameters);
|
||||
if (
|
||||
result.application.application_path !== parameters.application_path ||
|
||||
!isPathWithinRoot(
|
||||
@@ -37,7 +48,8 @@ export const parseActiveElectronCapture = (
|
||||
result.application.application_path,
|
||||
)
|
||||
)
|
||||
throw new TypeError(
|
||||
throw invalidInput(
|
||||
["normalized_result", "application", "application_path"],
|
||||
"Active Electron Evidence application path disagrees with its configured root",
|
||||
);
|
||||
return {
|
||||
@@ -62,11 +74,11 @@ const assertIdentity = (evidence: Evidence): void => {
|
||||
evidence.authority !== "controlled-replay" ||
|
||||
evidence.confidence !== "observed"
|
||||
)
|
||||
throw new TypeError(
|
||||
throw invalidInput(
|
||||
[],
|
||||
"Evidence does not match the supported capture_electron_scenario contract",
|
||||
);
|
||||
};
|
||||
|
||||
const normalizeInspection = (
|
||||
result: ElectronActiveObservationResult,
|
||||
): {
|
||||
|
||||
@@ -0,0 +1,481 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
browserAllowedOriginsSchema,
|
||||
browserEndpointSchema,
|
||||
} from "../browserObservation.js";
|
||||
import {
|
||||
webPageInspectionSchema,
|
||||
type WebPageInspection,
|
||||
} from "../browserObservationSchemas.js";
|
||||
import {
|
||||
classifyBrowserCompleteness,
|
||||
type BrowserCompleteness,
|
||||
} from "../browserCompleteness.js";
|
||||
import {
|
||||
electronPageInspectionSchema,
|
||||
type ElectronPageInspection,
|
||||
} from "./electronObservation.js";
|
||||
import {
|
||||
javascriptRuntimeObservationSchema,
|
||||
javascriptRuntimeKindSchema,
|
||||
type JavaScriptRuntimeObservation,
|
||||
type JavaScriptRuntimeTargetLocation,
|
||||
} from "./javascriptRuntimeObservation.js";
|
||||
import { digestCanonicalValue } from "../canonicalDigest.js";
|
||||
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
|
||||
import { parseEvidence, type Evidence } from "../evidence.js";
|
||||
import { parseActiveElectronCapture } from "./javascriptRuntimeReconciliationActive.js";
|
||||
import {
|
||||
assertEvidenceIdentity,
|
||||
invalidInput,
|
||||
parseAtPath,
|
||||
} from "./javascriptRuntimeReconciliationInputValidation.js";
|
||||
|
||||
interface RuntimeCaptureBase {
|
||||
readonly evidence: Evidence;
|
||||
readonly captureSha256: string;
|
||||
readonly scriptsCompleteWithinScope: boolean;
|
||||
}
|
||||
|
||||
interface NormalizedV8Inspection {
|
||||
readonly target:
|
||||
| {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly file_path: string;
|
||||
}
|
||||
| {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly url: string;
|
||||
}
|
||||
| {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly unresolved_location: Extract<
|
||||
JavaScriptRuntimeObservation["target"]["location"],
|
||||
{ kind: "unresolved" }
|
||||
>;
|
||||
};
|
||||
readonly frames: readonly [];
|
||||
readonly scripts: {
|
||||
readonly items: readonly (Readonly<{
|
||||
script_key: string;
|
||||
frame_id: string | null;
|
||||
cdp_hash: string | null;
|
||||
length: number | null;
|
||||
is_module: boolean | null;
|
||||
language: null;
|
||||
source: { readonly included: false; readonly reason: string };
|
||||
}> &
|
||||
(
|
||||
| { readonly file_path: string }
|
||||
| { readonly url: string }
|
||||
| {
|
||||
readonly unresolved_location: Extract<
|
||||
JavaScriptRuntimeObservation["scripts"]["items"][number]["location"],
|
||||
{ kind: "unresolved" }
|
||||
>;
|
||||
}
|
||||
))[];
|
||||
};
|
||||
readonly workers: readonly [];
|
||||
readonly completeness: BrowserCompleteness;
|
||||
}
|
||||
|
||||
export type ParsedRuntimeCapture =
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "browser";
|
||||
readonly inspection: WebPageInspection;
|
||||
})
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "electron";
|
||||
readonly inspection: ElectronPageInspection;
|
||||
})
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "v8-inspector";
|
||||
readonly inspection: NormalizedV8Inspection;
|
||||
})
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "electron-active";
|
||||
readonly inspection: {
|
||||
readonly target: {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly file_path: string;
|
||||
};
|
||||
readonly frames: readonly [];
|
||||
readonly scripts: { readonly items: readonly [] };
|
||||
readonly workers: readonly [];
|
||||
readonly completeness: BrowserCompleteness;
|
||||
};
|
||||
});
|
||||
|
||||
/** Parse only supported passive web/Electron inspection Evidence. */
|
||||
export const parseRuntimeCaptures = (
|
||||
observations: readonly Evidence[],
|
||||
path: readonly (string | number)[] = ["runtime_observations"],
|
||||
): ParsedRuntimeCapture[] =>
|
||||
observations
|
||||
.map((observation, index) =>
|
||||
parseRuntimeCapture(observation, [...path, index]),
|
||||
)
|
||||
.sort((left, right) =>
|
||||
compareUnicodeCodePoints(
|
||||
left.evidence.evidence_id,
|
||||
right.evidence.evidence_id,
|
||||
),
|
||||
);
|
||||
|
||||
const parseRuntimeCapture = (
|
||||
input: Evidence,
|
||||
evidencePath: readonly (string | number)[],
|
||||
): ParsedRuntimeCapture => {
|
||||
const evidence = parseAtPath(parseEvidence, input, evidencePath);
|
||||
if (evidence.operation === "inspect_web_page")
|
||||
return parseBrowserCapture(evidence, evidencePath);
|
||||
if (evidence.operation === "inspect_electron_page")
|
||||
return parseElectronCapture(evidence, evidencePath);
|
||||
if (evidence.operation === "observe_javascript_runtime")
|
||||
return parseV8Capture(evidence, evidencePath);
|
||||
if (evidence.operation === "capture_electron_scenario") {
|
||||
return parseAtPath(
|
||||
() => parseActiveElectronCapture(evidence),
|
||||
evidence,
|
||||
evidencePath,
|
||||
);
|
||||
}
|
||||
throw invalidInput(
|
||||
evidencePath,
|
||||
"Runtime reconciliation requires inspect_web_page, inspect_electron_page, observe_javascript_runtime, or capture_electron_scenario Evidence",
|
||||
);
|
||||
};
|
||||
|
||||
const parseBrowserCapture = (
|
||||
evidence: Evidence,
|
||||
path: readonly (string | number)[],
|
||||
): ParsedRuntimeCapture => {
|
||||
assertEvidenceIdentity(
|
||||
evidence,
|
||||
{
|
||||
operation: "inspect_web_page",
|
||||
predicate: "rea.web-page-inspection",
|
||||
providerId: "rea-cdp-browser",
|
||||
providerName: "REA Chrome DevTools Protocol observation provider",
|
||||
providerVersion: "2",
|
||||
authority: "external-service",
|
||||
confidence: "observed",
|
||||
},
|
||||
path,
|
||||
);
|
||||
const inspection = parseAtPath(
|
||||
(value) => webPageInspectionSchema.parse(value),
|
||||
evidence.normalized_result,
|
||||
[...path, "normalized_result"],
|
||||
);
|
||||
assertRuntimeParameters(
|
||||
evidence,
|
||||
{
|
||||
kind: "browser",
|
||||
targetId: inspection.target.target_id,
|
||||
targetOrigin: inspection.target.origin,
|
||||
sourceIncluded: inspection.scripts.items.some(
|
||||
({ source }) => source.included,
|
||||
),
|
||||
},
|
||||
path,
|
||||
);
|
||||
return {
|
||||
kind: "browser",
|
||||
evidence,
|
||||
inspection,
|
||||
captureSha256: digestCanonicalValue(inspection, "Runtime reconciliation"),
|
||||
scriptsCompleteWithinScope: scriptsComplete(inspection.completeness),
|
||||
};
|
||||
};
|
||||
|
||||
const parseElectronCapture = (
|
||||
evidence: Evidence,
|
||||
path: readonly (string | number)[],
|
||||
): ParsedRuntimeCapture => {
|
||||
assertEvidenceIdentity(
|
||||
evidence,
|
||||
{
|
||||
operation: "inspect_electron_page",
|
||||
predicate: "rea.electron-page-inspection",
|
||||
providerId: "rea-cdp-electron",
|
||||
providerName: "REA Electron file-page CDP observation provider",
|
||||
providerVersion: "1",
|
||||
authority: "external-service",
|
||||
confidence: "observed",
|
||||
},
|
||||
path,
|
||||
);
|
||||
const inspection = parseAtPath(
|
||||
(value) => electronPageInspectionSchema.parse(value),
|
||||
evidence.normalized_result,
|
||||
[...path, "normalized_result"],
|
||||
);
|
||||
assertRuntimeParameters(
|
||||
evidence,
|
||||
{
|
||||
kind: "electron",
|
||||
targetId: inspection.target.target_id,
|
||||
sourceIncluded: inspection.scripts.items.some(
|
||||
({ source }) => source.included,
|
||||
),
|
||||
},
|
||||
path,
|
||||
);
|
||||
return {
|
||||
kind: "electron",
|
||||
evidence,
|
||||
inspection,
|
||||
captureSha256: digestCanonicalValue(inspection, "Runtime reconciliation"),
|
||||
scriptsCompleteWithinScope: scriptsComplete(inspection.completeness),
|
||||
};
|
||||
};
|
||||
|
||||
const parseV8Capture = (
|
||||
evidence: Evidence,
|
||||
path: readonly (string | number)[],
|
||||
): ParsedRuntimeCapture => {
|
||||
assertEvidenceIdentity(
|
||||
evidence,
|
||||
{
|
||||
operation: "observe_javascript_runtime",
|
||||
predicate: "rea.javascript-runtime-observation",
|
||||
providerId: "rea-v8-inspector",
|
||||
providerName: "REA passive Node/Electron V8 Inspector provider",
|
||||
providerVersion: "1",
|
||||
authority: "external-service",
|
||||
confidence: "observed",
|
||||
},
|
||||
path,
|
||||
);
|
||||
const result = parseAtPath(
|
||||
(value) => javascriptRuntimeObservationSchema.parse(value),
|
||||
evidence.normalized_result,
|
||||
[...path, "normalized_result"],
|
||||
);
|
||||
assertV8RuntimeParameters(evidence, result, path);
|
||||
return {
|
||||
kind: "v8-inspector",
|
||||
evidence,
|
||||
inspection: normalizeV8Inspection(result),
|
||||
captureSha256: digestCanonicalValue(result, "Runtime reconciliation"),
|
||||
scriptsCompleteWithinScope: false,
|
||||
};
|
||||
};
|
||||
|
||||
const assertV8RuntimeParameters = (
|
||||
evidence: Evidence,
|
||||
result: JavaScriptRuntimeObservation,
|
||||
path: readonly (string | number)[],
|
||||
): void => {
|
||||
const parameters = parseAtPath(
|
||||
(value) =>
|
||||
z
|
||||
.object({
|
||||
inspector_endpoint: browserEndpointSchema,
|
||||
target_id: z.string().trim().min(1),
|
||||
runtime_kind: javascriptRuntimeKindSchema.optional(),
|
||||
})
|
||||
.passthrough()
|
||||
.parse(value),
|
||||
evidence.parameters,
|
||||
[...path, "parameters"],
|
||||
);
|
||||
if (
|
||||
parameters.target_id !== result.target.target_id ||
|
||||
(parameters.runtime_kind !== undefined &&
|
||||
parameters.runtime_kind !== result.target.runtime_kind)
|
||||
)
|
||||
throw invalidInput(
|
||||
[...path, "parameters", "target_id"],
|
||||
"Runtime Evidence target or declared role disagrees with its result",
|
||||
);
|
||||
if (
|
||||
result.target.location.kind === "builtin" &&
|
||||
!result.target.location.specifier.startsWith("node:")
|
||||
)
|
||||
throw invalidInput(
|
||||
[...path, "normalized_result", "target", "location"],
|
||||
"Runtime Evidence contains an invalid builtin location",
|
||||
);
|
||||
for (const [index, { location }] of result.scripts.items.entries())
|
||||
if (location.kind === "builtin" && !location.specifier.startsWith("node:"))
|
||||
throw invalidInput(
|
||||
[...path, "normalized_result", "scripts", "items", index, "location"],
|
||||
"Runtime Evidence contains an invalid builtin location",
|
||||
);
|
||||
};
|
||||
|
||||
const normalizeV8Inspection = (
|
||||
result: JavaScriptRuntimeObservation,
|
||||
): NormalizedV8Inspection => ({
|
||||
target: {
|
||||
target_id: result.target.target_id,
|
||||
type: result.target.protocol_type,
|
||||
title: result.target.runtime_kind,
|
||||
attached: result.target.attached,
|
||||
...(result.target.location.kind === "unresolved"
|
||||
? { unresolved_location: result.target.location }
|
||||
: runtimeLocation(result.target.location)),
|
||||
},
|
||||
frames: [],
|
||||
scripts: {
|
||||
items: result.scripts.items.map((script) => ({
|
||||
script_key: script.script_key,
|
||||
frame_id: script.execution_context_key,
|
||||
...runtimeLocation(script.location),
|
||||
cdp_hash: script.cdp_hash,
|
||||
length: script.length,
|
||||
is_module: script.is_module,
|
||||
language: null,
|
||||
source: {
|
||||
included: false,
|
||||
reason: "V8 Inspector source capture is outside passive authority.",
|
||||
},
|
||||
})),
|
||||
},
|
||||
workers: [],
|
||||
completeness: classifyBrowserCompleteness({
|
||||
policyFilteredSections: new Set(
|
||||
excludedV8Scripts(result) > 0 ? ["scripts"] : [],
|
||||
),
|
||||
attachLimitedSections: new Set([
|
||||
"frames",
|
||||
"scripts",
|
||||
"script_sources",
|
||||
"workers",
|
||||
]),
|
||||
truncatedSections: new Set(result.capture.truncated ? ["scripts"] : []),
|
||||
unavailableSections: new Set(["frames", "script_sources", "workers"]),
|
||||
excluded:
|
||||
excludedV8Scripts(result) === 0
|
||||
? []
|
||||
: [
|
||||
{
|
||||
section: "scripts",
|
||||
reason: "out_of_target_scope",
|
||||
count: excludedV8Scripts(result),
|
||||
},
|
||||
],
|
||||
droppedEvents: {
|
||||
scripts: result.capture.events_dropped,
|
||||
network_requests: 0,
|
||||
console_events: 0,
|
||||
websocket_connections: 0,
|
||||
websocket_frames: 0,
|
||||
webmcp_tools: 0,
|
||||
timeline_events: 0,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const runtimeLocation = (
|
||||
location: JavaScriptRuntimeTargetLocation,
|
||||
):
|
||||
| { readonly file_path: string }
|
||||
| { readonly url: string }
|
||||
| {
|
||||
readonly unresolved_location: Extract<
|
||||
JavaScriptRuntimeTargetLocation,
|
||||
{ kind: "unresolved" }
|
||||
>;
|
||||
} => {
|
||||
if (location.kind === "unresolved") return { unresolved_location: location };
|
||||
if (location.kind === "file") return { file_path: location.file_path };
|
||||
if (location.kind === "url") return { url: location.sanitized_url };
|
||||
return { url: location.specifier };
|
||||
};
|
||||
|
||||
const excludedV8Scripts = (result: JavaScriptRuntimeObservation): number =>
|
||||
Object.values(result.scripts.excluded).reduce(
|
||||
(total, count) => total + count,
|
||||
0,
|
||||
);
|
||||
|
||||
const assertRuntimeParameters = (
|
||||
evidence: Evidence,
|
||||
expected:
|
||||
| {
|
||||
readonly kind: "browser";
|
||||
readonly targetId: string;
|
||||
readonly targetOrigin: string;
|
||||
readonly sourceIncluded: boolean;
|
||||
}
|
||||
| {
|
||||
readonly kind: "electron";
|
||||
readonly targetId: string;
|
||||
readonly sourceIncluded: boolean;
|
||||
},
|
||||
path: readonly (string | number)[],
|
||||
): void => {
|
||||
const common = {
|
||||
target_id: z.string().trim().min(1),
|
||||
cdp_endpoint: browserEndpointSchema,
|
||||
include_script_sources: z.boolean(),
|
||||
};
|
||||
if (expected.kind === "browser") {
|
||||
const parameters = parseAtPath(
|
||||
(value) =>
|
||||
z
|
||||
.object({ ...common, allowed_origins: browserAllowedOriginsSchema })
|
||||
.passthrough()
|
||||
.parse(value),
|
||||
evidence.parameters,
|
||||
[...path, "parameters"],
|
||||
);
|
||||
if (parameters.target_id !== expected.targetId)
|
||||
throw invalidInput(
|
||||
[...path, "parameters", "target_id"],
|
||||
"Runtime Evidence target disagrees with its captured result",
|
||||
);
|
||||
if (!parameters.allowed_origins.includes(expected.targetOrigin))
|
||||
throw invalidInput(
|
||||
[...path, "parameters", "allowed_origins"],
|
||||
"Browser Evidence target is outside its recorded origin scope",
|
||||
);
|
||||
if (expected.sourceIncluded && !parameters.include_script_sources)
|
||||
throw invalidInput(
|
||||
[...path, "parameters", "include_script_sources"],
|
||||
"Runtime Evidence contains source without source-capture selection",
|
||||
);
|
||||
return;
|
||||
}
|
||||
const parameters = parseAtPath(
|
||||
(value) => z.object(common).passthrough().parse(value),
|
||||
evidence.parameters,
|
||||
[...path, "parameters"],
|
||||
);
|
||||
if (parameters.target_id !== expected.targetId)
|
||||
throw invalidInput(
|
||||
[...path, "parameters", "target_id"],
|
||||
"Runtime Evidence target disagrees with its captured result",
|
||||
);
|
||||
if (expected.sourceIncluded && !parameters.include_script_sources)
|
||||
throw invalidInput(
|
||||
[...path, "parameters", "include_script_sources"],
|
||||
"Runtime Evidence contains source without source-capture selection",
|
||||
);
|
||||
};
|
||||
|
||||
const scriptsComplete = (completeness: {
|
||||
readonly truncated_sections: readonly string[];
|
||||
readonly unavailable_sections: readonly string[];
|
||||
readonly dropped_events: { readonly scripts: number };
|
||||
}): boolean =>
|
||||
!completeness.truncated_sections.includes("scripts") &&
|
||||
!completeness.unavailable_sections.includes("scripts") &&
|
||||
completeness.dropped_events.scripts === 0;
|
||||
@@ -7,10 +7,8 @@ import type {
|
||||
ApplicationEdge,
|
||||
ApplicationNode,
|
||||
} from "./javascriptApplicationGraphSchemas.js";
|
||||
import type {
|
||||
ParsedRuntimeCapture,
|
||||
ParsedStaticLayer,
|
||||
} from "./javascriptRuntimeReconciliationParsing.js";
|
||||
import type { ParsedStaticLayer } from "./javascriptRuntimeReconciliationParsing.js";
|
||||
import type { ParsedRuntimeCapture } from "./javascriptRuntimeReconciliationCaptureParsing.js";
|
||||
import { uniqueSorted } from "../canonicalOrdering.js";
|
||||
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
|
||||
import type { RuntimeProjection } from "./javascriptRuntimeReconciliationRuntime.js";
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { z } from "zod";
|
||||
import type { Evidence } from "../evidence.js";
|
||||
|
||||
/** Prefix caller paths on a nested Zod validation boundary. */
|
||||
export const parseAtPath = <Value>(
|
||||
parse: (input: unknown) => Value,
|
||||
input: unknown,
|
||||
path: readonly (string | number)[],
|
||||
): Value => {
|
||||
try {
|
||||
return parse(input);
|
||||
} catch (cause: unknown) {
|
||||
if (cause instanceof z.ZodError)
|
||||
throw new z.ZodError(
|
||||
cause.issues.map((issue) => ({
|
||||
...issue,
|
||||
path: [...path, ...issue.path],
|
||||
})),
|
||||
);
|
||||
throw cause;
|
||||
}
|
||||
};
|
||||
|
||||
/** Represent one semantic caller constraint as a standard validation issue. */
|
||||
export const invalidInput = (
|
||||
path: readonly (string | number)[],
|
||||
message: string,
|
||||
): z.ZodError => new z.ZodError([{ code: "custom", path: [...path], message }]);
|
||||
|
||||
/** Verify an authenticated Evidence record against one runtime workflow. */
|
||||
export const assertEvidenceIdentity = (
|
||||
evidence: Evidence,
|
||||
expected: {
|
||||
readonly operation: string;
|
||||
readonly predicate: string;
|
||||
readonly providerId: string;
|
||||
readonly providerName: string;
|
||||
readonly providerVersion: string;
|
||||
readonly authority: Evidence["authority"];
|
||||
readonly confidence: Evidence["confidence"];
|
||||
},
|
||||
path: readonly (string | number)[],
|
||||
): void => {
|
||||
if (
|
||||
evidence.operation !== expected.operation ||
|
||||
evidence.predicate_type !== expected.predicate ||
|
||||
evidence.provider.id !== expected.providerId ||
|
||||
evidence.provider.name !== expected.providerName ||
|
||||
evidence.provider.version !== expected.providerVersion ||
|
||||
evidence.authority !== expected.authority ||
|
||||
evidence.confidence !== expected.confidence
|
||||
)
|
||||
throw invalidInput(
|
||||
path,
|
||||
`Evidence does not match the supported ${expected.operation} contract`,
|
||||
);
|
||||
};
|
||||
@@ -1,27 +1,3 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
browserAllowedOriginsSchema,
|
||||
browserEndpointSchema,
|
||||
} from "../browserObservation.js";
|
||||
import {
|
||||
webPageInspectionSchema,
|
||||
type WebPageInspection,
|
||||
} from "../browserObservationSchemas.js";
|
||||
import {
|
||||
classifyBrowserCompleteness,
|
||||
type BrowserCompleteness,
|
||||
} from "../browserCompleteness.js";
|
||||
import {
|
||||
electronPageInspectionSchema,
|
||||
type ElectronPageInspection,
|
||||
} from "./electronObservation.js";
|
||||
import {
|
||||
javascriptRuntimeObservationSchema,
|
||||
javascriptRuntimeKindSchema,
|
||||
type JavaScriptRuntimeObservation,
|
||||
type JavaScriptRuntimeTargetLocation,
|
||||
} from "./javascriptRuntimeObservation.js";
|
||||
import { digestCanonicalValue } from "../canonicalDigest.js";
|
||||
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
|
||||
import { parseEvidence, type Evidence } from "../evidence.js";
|
||||
@@ -29,9 +5,13 @@ import {
|
||||
javascriptApplicationAnalysisResultSchema,
|
||||
type JavaScriptApplicationAnalysisResult,
|
||||
} from "./javascriptApplicationAnalysis.js";
|
||||
import { type JavaScriptApplicationGraph } from "./javascriptApplicationGraph.js";
|
||||
import { parseActiveElectronCapture } from "./javascriptRuntimeReconciliationActive.js";
|
||||
import type { JavaScriptApplicationGraph } from "./javascriptApplicationGraph.js";
|
||||
import type { ReconcileJavaScriptRuntimeInput } from "./javascriptRuntimeReconciliationSchemas.js";
|
||||
import {
|
||||
assertEvidenceIdentity,
|
||||
invalidInput,
|
||||
parseAtPath,
|
||||
} from "./javascriptRuntimeReconciliationInputValidation.js";
|
||||
|
||||
type StaticLayerInput =
|
||||
ReconcileJavaScriptRuntimeInput["static_layers"][number];
|
||||
@@ -46,138 +26,50 @@ export interface ParsedStaticLayer {
|
||||
readonly runtimeMappings: readonly RuntimeMapping[];
|
||||
}
|
||||
|
||||
interface RuntimeCaptureBase {
|
||||
readonly evidence: Evidence;
|
||||
readonly captureSha256: string;
|
||||
readonly scriptsCompleteWithinScope: boolean;
|
||||
}
|
||||
|
||||
interface NormalizedV8Inspection {
|
||||
readonly target:
|
||||
| {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly file_path: string;
|
||||
}
|
||||
| {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly url: string;
|
||||
}
|
||||
| {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly unresolved_location: Extract<
|
||||
JavaScriptRuntimeObservation["target"]["location"],
|
||||
{ kind: "unresolved" }
|
||||
>;
|
||||
};
|
||||
readonly frames: readonly [];
|
||||
readonly scripts: {
|
||||
readonly items: readonly (Readonly<{
|
||||
script_key: string;
|
||||
frame_id: string | null;
|
||||
cdp_hash: string | null;
|
||||
length: number | null;
|
||||
is_module: boolean | null;
|
||||
language: null;
|
||||
source: { readonly included: false; readonly reason: string };
|
||||
}> &
|
||||
(
|
||||
| { readonly file_path: string }
|
||||
| { readonly url: string }
|
||||
| {
|
||||
readonly unresolved_location: Extract<
|
||||
JavaScriptRuntimeObservation["scripts"]["items"][number]["location"],
|
||||
{ kind: "unresolved" }
|
||||
>;
|
||||
}
|
||||
))[];
|
||||
};
|
||||
readonly workers: readonly [];
|
||||
readonly completeness: BrowserCompleteness;
|
||||
}
|
||||
|
||||
export type ParsedRuntimeCapture =
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "browser";
|
||||
readonly inspection: WebPageInspection;
|
||||
})
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "electron";
|
||||
readonly inspection: ElectronPageInspection;
|
||||
})
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "v8-inspector";
|
||||
readonly inspection: NormalizedV8Inspection;
|
||||
})
|
||||
| (RuntimeCaptureBase & {
|
||||
readonly kind: "electron-active";
|
||||
readonly inspection: {
|
||||
readonly target: {
|
||||
readonly target_id: string;
|
||||
readonly type: string;
|
||||
readonly title: string;
|
||||
readonly attached: boolean;
|
||||
readonly file_path: string;
|
||||
};
|
||||
readonly frames: readonly [];
|
||||
readonly scripts: { readonly items: readonly [] };
|
||||
readonly workers: readonly [];
|
||||
readonly completeness: BrowserCompleteness;
|
||||
};
|
||||
});
|
||||
|
||||
/** Parse and semantically bind every static analysis Evidence layer. */
|
||||
export const parseStaticLayers = (
|
||||
layers: readonly StaticLayerInput[],
|
||||
path: readonly (string | number)[] = ["static_layers"],
|
||||
): ParsedStaticLayer[] =>
|
||||
layers
|
||||
.map((layer) => parseStaticLayer(layer))
|
||||
.map((layer, index) =>
|
||||
parseStaticLayer(layer, [...path, index, "analysis"]),
|
||||
)
|
||||
.sort((left, right) =>
|
||||
compareUnicodeCodePoints(left.layerId, right.layerId),
|
||||
);
|
||||
|
||||
/** Parse only supported passive web/Electron inspection Evidence. */
|
||||
export const parseRuntimeCaptures = (
|
||||
observations: readonly Evidence[],
|
||||
): ParsedRuntimeCapture[] =>
|
||||
observations
|
||||
.map((observation) => parseRuntimeCapture(observation))
|
||||
.sort((left, right) =>
|
||||
compareUnicodeCodePoints(
|
||||
left.evidence.evidence_id,
|
||||
right.evidence.evidence_id,
|
||||
),
|
||||
);
|
||||
|
||||
const parseStaticLayer = (layer: StaticLayerInput): ParsedStaticLayer => {
|
||||
const evidence = parseEvidence(layer.analysis);
|
||||
const result = javascriptApplicationAnalysisResultSchema.parse(
|
||||
const parseStaticLayer = (
|
||||
layer: StaticLayerInput,
|
||||
evidencePath: readonly (string | number)[],
|
||||
): ParsedStaticLayer => {
|
||||
const evidence = parseAtPath(parseEvidence, layer.analysis, evidencePath);
|
||||
const result = parseAtPath(
|
||||
(value) => javascriptApplicationAnalysisResultSchema.parse(value),
|
||||
evidence.normalized_result,
|
||||
[...evidencePath, "normalized_result"],
|
||||
);
|
||||
assertEvidenceIdentity(
|
||||
evidence,
|
||||
{
|
||||
operation: "analyze_javascript_application",
|
||||
predicate: "rea.javascript-application-analysis",
|
||||
providerId: "rea-javascript-application",
|
||||
providerName: "REA JavaScript application analyzer",
|
||||
providerVersion: "1",
|
||||
authority: "shipped-artifact",
|
||||
confidence: "derived",
|
||||
},
|
||||
evidencePath,
|
||||
);
|
||||
assertEvidenceIdentity(evidence, {
|
||||
operation: "analyze_javascript_application",
|
||||
predicate: "rea.javascript-application-analysis",
|
||||
providerId: "rea-javascript-application",
|
||||
providerName: "REA JavaScript application analyzer",
|
||||
providerVersion: "1",
|
||||
authority: "shipped-artifact",
|
||||
confidence: "derived",
|
||||
});
|
||||
if (
|
||||
evidence.subject === null ||
|
||||
evidence.subject.digest.sha256 !== result.root_artifact_sha256 ||
|
||||
evidence.subject.format !== result.format ||
|
||||
evidence.subject.local_path !== result.input_path
|
||||
)
|
||||
throw new TypeError(
|
||||
throw invalidInput(
|
||||
[...evidencePath, "subject"],
|
||||
"JavaScript application Evidence subject disagrees with its result",
|
||||
);
|
||||
return {
|
||||
@@ -196,294 +88,3 @@ const parseStaticLayer = (layer: StaticLayerInput): ParsedStaticLayer => {
|
||||
runtimeMappings: layer.runtime_mappings,
|
||||
};
|
||||
};
|
||||
|
||||
const parseRuntimeCapture = (input: Evidence): ParsedRuntimeCapture => {
|
||||
const evidence = parseEvidence(input);
|
||||
if (evidence.operation === "inspect_web_page") {
|
||||
assertEvidenceIdentity(evidence, {
|
||||
operation: "inspect_web_page",
|
||||
predicate: "rea.web-page-inspection",
|
||||
providerId: "rea-cdp-browser",
|
||||
providerName: "REA Chrome DevTools Protocol observation provider",
|
||||
providerVersion: "2",
|
||||
authority: "external-service",
|
||||
confidence: "observed",
|
||||
});
|
||||
const inspection = webPageInspectionSchema.parse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
assertRuntimeParameters(evidence, {
|
||||
kind: "browser",
|
||||
targetId: inspection.target.target_id,
|
||||
targetOrigin: inspection.target.origin,
|
||||
sourceIncluded: inspection.scripts.items.some(
|
||||
({ source }) => source.included,
|
||||
),
|
||||
});
|
||||
return {
|
||||
kind: "browser",
|
||||
evidence,
|
||||
inspection,
|
||||
captureSha256: digestCanonicalValue(inspection, "Runtime reconciliation"),
|
||||
scriptsCompleteWithinScope: scriptsComplete(inspection.completeness),
|
||||
};
|
||||
}
|
||||
if (evidence.operation === "inspect_electron_page") {
|
||||
assertEvidenceIdentity(evidence, {
|
||||
operation: "inspect_electron_page",
|
||||
predicate: "rea.electron-page-inspection",
|
||||
providerId: "rea-cdp-electron",
|
||||
providerName: "REA Electron file-page CDP observation provider",
|
||||
providerVersion: "1",
|
||||
authority: "external-service",
|
||||
confidence: "observed",
|
||||
});
|
||||
const inspection = electronPageInspectionSchema.parse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
assertRuntimeParameters(evidence, {
|
||||
kind: "electron",
|
||||
targetId: inspection.target.target_id,
|
||||
sourceIncluded: inspection.scripts.items.some(
|
||||
({ source }) => source.included,
|
||||
),
|
||||
});
|
||||
return {
|
||||
kind: "electron",
|
||||
evidence,
|
||||
inspection,
|
||||
captureSha256: digestCanonicalValue(inspection, "Runtime reconciliation"),
|
||||
scriptsCompleteWithinScope: scriptsComplete(inspection.completeness),
|
||||
};
|
||||
}
|
||||
if (evidence.operation === "observe_javascript_runtime") {
|
||||
assertEvidenceIdentity(evidence, {
|
||||
operation: "observe_javascript_runtime",
|
||||
predicate: "rea.javascript-runtime-observation",
|
||||
providerId: "rea-v8-inspector",
|
||||
providerName: "REA passive Node/Electron V8 Inspector provider",
|
||||
providerVersion: "1",
|
||||
authority: "external-service",
|
||||
confidence: "observed",
|
||||
});
|
||||
const result = javascriptRuntimeObservationSchema.parse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
assertV8RuntimeParameters(evidence, result);
|
||||
const inspection = normalizeV8Inspection(result);
|
||||
return {
|
||||
kind: "v8-inspector",
|
||||
evidence,
|
||||
inspection,
|
||||
captureSha256: digestCanonicalValue(result, "Runtime reconciliation"),
|
||||
scriptsCompleteWithinScope: false,
|
||||
};
|
||||
}
|
||||
if (evidence.operation === "capture_electron_scenario") {
|
||||
return parseActiveElectronCapture(evidence);
|
||||
}
|
||||
throw new TypeError(
|
||||
"Runtime reconciliation requires inspect_web_page, inspect_electron_page, observe_javascript_runtime, or capture_electron_scenario Evidence",
|
||||
);
|
||||
};
|
||||
|
||||
const assertV8RuntimeParameters = (
|
||||
evidence: Evidence,
|
||||
result: JavaScriptRuntimeObservation,
|
||||
): void => {
|
||||
const parameters = z
|
||||
.object({
|
||||
inspector_endpoint: browserEndpointSchema,
|
||||
target_id: z.string().trim().min(1),
|
||||
runtime_kind: javascriptRuntimeKindSchema.optional(),
|
||||
})
|
||||
.passthrough()
|
||||
.parse(evidence.parameters);
|
||||
if (
|
||||
parameters.target_id !== result.target.target_id ||
|
||||
(parameters.runtime_kind !== undefined &&
|
||||
parameters.runtime_kind !== result.target.runtime_kind)
|
||||
)
|
||||
throw new TypeError(
|
||||
"Runtime Evidence target or declared role disagrees with its result",
|
||||
);
|
||||
for (const location of [
|
||||
result.target.location,
|
||||
...result.scripts.items.map(({ location }) => location),
|
||||
])
|
||||
if (location.kind === "builtin" && !location.specifier.startsWith("node:"))
|
||||
throw new TypeError(
|
||||
"Runtime Evidence contains an invalid builtin location",
|
||||
);
|
||||
};
|
||||
|
||||
const normalizeV8Inspection = (
|
||||
result: JavaScriptRuntimeObservation,
|
||||
): NormalizedV8Inspection => ({
|
||||
target: {
|
||||
target_id: result.target.target_id,
|
||||
type: result.target.protocol_type,
|
||||
title: result.target.runtime_kind,
|
||||
attached: result.target.attached,
|
||||
...(result.target.location.kind === "unresolved"
|
||||
? { unresolved_location: result.target.location }
|
||||
: runtimeLocation(result.target.location)),
|
||||
},
|
||||
frames: [],
|
||||
scripts: {
|
||||
items: result.scripts.items.map((script) => ({
|
||||
script_key: script.script_key,
|
||||
frame_id: script.execution_context_key,
|
||||
...runtimeLocation(script.location),
|
||||
cdp_hash: script.cdp_hash,
|
||||
length: script.length,
|
||||
is_module: script.is_module,
|
||||
language: null,
|
||||
source: {
|
||||
included: false,
|
||||
reason: "V8 Inspector source capture is outside passive authority.",
|
||||
},
|
||||
})),
|
||||
},
|
||||
workers: [],
|
||||
completeness: classifyBrowserCompleteness({
|
||||
policyFilteredSections: new Set(
|
||||
excludedV8Scripts(result) > 0 ? ["scripts"] : [],
|
||||
),
|
||||
attachLimitedSections: new Set([
|
||||
"frames",
|
||||
"scripts",
|
||||
"script_sources",
|
||||
"workers",
|
||||
]),
|
||||
truncatedSections: new Set(result.capture.truncated ? ["scripts"] : []),
|
||||
unavailableSections: new Set(["frames", "script_sources", "workers"]),
|
||||
excluded:
|
||||
excludedV8Scripts(result) === 0
|
||||
? []
|
||||
: [
|
||||
{
|
||||
section: "scripts",
|
||||
reason: "out_of_target_scope",
|
||||
count: excludedV8Scripts(result),
|
||||
},
|
||||
],
|
||||
droppedEvents: {
|
||||
scripts: result.capture.events_dropped,
|
||||
network_requests: 0,
|
||||
console_events: 0,
|
||||
websocket_connections: 0,
|
||||
websocket_frames: 0,
|
||||
webmcp_tools: 0,
|
||||
timeline_events: 0,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const runtimeLocation = (
|
||||
location: JavaScriptRuntimeTargetLocation,
|
||||
):
|
||||
| { readonly file_path: string }
|
||||
| { readonly url: string }
|
||||
| {
|
||||
readonly unresolved_location: Extract<
|
||||
JavaScriptRuntimeTargetLocation,
|
||||
{ kind: "unresolved" }
|
||||
>;
|
||||
} => {
|
||||
if (location.kind === "unresolved") return { unresolved_location: location };
|
||||
if (location.kind === "file") return { file_path: location.file_path };
|
||||
if (location.kind === "url") return { url: location.sanitized_url };
|
||||
return { url: location.specifier };
|
||||
};
|
||||
|
||||
const excludedV8Scripts = (result: JavaScriptRuntimeObservation): number =>
|
||||
Object.values(result.scripts.excluded).reduce(
|
||||
(total, count) => total + count,
|
||||
0,
|
||||
);
|
||||
|
||||
const assertRuntimeParameters = (
|
||||
evidence: Evidence,
|
||||
expected:
|
||||
| {
|
||||
readonly kind: "browser";
|
||||
readonly targetId: string;
|
||||
readonly targetOrigin: string;
|
||||
readonly sourceIncluded: boolean;
|
||||
}
|
||||
| {
|
||||
readonly kind: "electron";
|
||||
readonly targetId: string;
|
||||
readonly sourceIncluded: boolean;
|
||||
},
|
||||
): void => {
|
||||
const common = {
|
||||
target_id: z.string().trim().min(1),
|
||||
cdp_endpoint: browserEndpointSchema,
|
||||
include_script_sources: z.boolean(),
|
||||
};
|
||||
if (expected.kind === "browser") {
|
||||
const parameters = z
|
||||
.object({ ...common, allowed_origins: browserAllowedOriginsSchema })
|
||||
.passthrough()
|
||||
.parse(evidence.parameters);
|
||||
if (parameters.target_id !== expected.targetId)
|
||||
throw new TypeError(
|
||||
"Runtime Evidence target disagrees with its captured result",
|
||||
);
|
||||
if (!parameters.allowed_origins.includes(expected.targetOrigin))
|
||||
throw new TypeError(
|
||||
"Browser Evidence target is outside its recorded origin scope",
|
||||
);
|
||||
if (expected.sourceIncluded && !parameters.include_script_sources)
|
||||
throw new TypeError(
|
||||
"Runtime Evidence contains source without source-capture selection",
|
||||
);
|
||||
return;
|
||||
}
|
||||
const parameters = z.object(common).passthrough().parse(evidence.parameters);
|
||||
if (parameters.target_id !== expected.targetId)
|
||||
throw new TypeError(
|
||||
"Runtime Evidence target disagrees with its captured result",
|
||||
);
|
||||
if (expected.sourceIncluded && !parameters.include_script_sources)
|
||||
throw new TypeError(
|
||||
"Runtime Evidence contains source without source-capture selection",
|
||||
);
|
||||
};
|
||||
|
||||
const scriptsComplete = (completeness: {
|
||||
readonly truncated_sections: readonly string[];
|
||||
readonly unavailable_sections: readonly string[];
|
||||
readonly dropped_events: { readonly scripts: number };
|
||||
}): boolean =>
|
||||
!completeness.truncated_sections.includes("scripts") &&
|
||||
!completeness.unavailable_sections.includes("scripts") &&
|
||||
completeness.dropped_events.scripts === 0;
|
||||
|
||||
const assertEvidenceIdentity = (
|
||||
evidence: Evidence,
|
||||
expected: {
|
||||
readonly operation: string;
|
||||
readonly predicate: string;
|
||||
readonly providerId: string;
|
||||
readonly providerName: string;
|
||||
readonly providerVersion: string;
|
||||
readonly authority: Evidence["authority"];
|
||||
readonly confidence: Evidence["confidence"];
|
||||
},
|
||||
): void => {
|
||||
if (
|
||||
evidence.operation !== expected.operation ||
|
||||
evidence.predicate_type !== expected.predicate ||
|
||||
evidence.provider.id !== expected.providerId ||
|
||||
evidence.provider.name !== expected.providerName ||
|
||||
evidence.provider.version !== expected.providerVersion ||
|
||||
evidence.authority !== expected.authority ||
|
||||
evidence.confidence !== expected.confidence
|
||||
)
|
||||
throw new TypeError(
|
||||
`Evidence does not match the supported ${expected.operation} contract`,
|
||||
);
|
||||
};
|
||||
@@ -3,10 +3,8 @@ import { digestCanonicalValue } from "../canonicalDigest.js";
|
||||
import { uniqueSorted } from "../canonicalOrdering.js";
|
||||
import type { StaticLoadStateProjection } from "./javascriptRuntimeLoadState.js";
|
||||
import type { RuntimeMatchingProjection } from "./javascriptRuntimeReconciliationMatching.js";
|
||||
import type {
|
||||
ParsedRuntimeCapture,
|
||||
ParsedStaticLayer,
|
||||
} from "./javascriptRuntimeReconciliationParsing.js";
|
||||
import type { ParsedStaticLayer } from "./javascriptRuntimeReconciliationParsing.js";
|
||||
import type { ParsedRuntimeCapture } from "./javascriptRuntimeReconciliationCaptureParsing.js";
|
||||
import {
|
||||
javascriptRuntimeReconciliationResultSchema,
|
||||
type JavaScriptRuntimeReconciliationResult,
|
||||
|
||||
@@ -8,7 +8,7 @@ import type {
|
||||
ApplicationNode,
|
||||
} from "./javascriptApplicationGraphSchemas.js";
|
||||
import type { ApplicationGraphEvidence } from "./javascriptApplicationEvidenceSchemas.js";
|
||||
import type { ParsedRuntimeCapture } from "./javascriptRuntimeReconciliationParsing.js";
|
||||
import type { ParsedRuntimeCapture } from "./javascriptRuntimeReconciliationCaptureParsing.js";
|
||||
|
||||
export interface RuntimeReconciliationEntity {
|
||||
readonly kind: "target" | "frame" | "script" | "worker";
|
||||
|
||||
@@ -12,7 +12,7 @@ import { publishWebScripts } from "../../../src/browser/assets/PublishWebScripts
|
||||
import { selectScriptCapture } from "../../../src/browser/assets/ScriptCaptureAdapters.js";
|
||||
import { inspectWebPageInputSchema } from "../../../src/domain/browserObservation.js";
|
||||
import { inspectElectronPageInputSchema } from "../../../src/domain/javascript/electronObservation.js";
|
||||
import { parseRuntimeCaptures } from "../../../src/domain/javascript/javascriptRuntimeReconciliationParsing.js";
|
||||
import { parseRuntimeCaptures } from "../../../src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js";
|
||||
import { projectRuntimeCaptures } from "../../../src/domain/javascript/javascriptRuntimeReconciliationRuntime.js";
|
||||
import { V8InspectorProvider } from "../../../src/inspector/V8InspectorProvider.js";
|
||||
import { startFakeCdpBrowser } from "../../fixtures/fakeCdpBrowser.js";
|
||||
|
||||
@@ -5,11 +5,13 @@ import { pathToFileURL } from "node:url";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { createJavaScriptRuntimeObservationEvidence } from "../../../src/application/javascript/JavaScriptRuntimeObservationEvidence.js";
|
||||
import { createBrowserEvidence } from "../../../src/application/BrowserEvidence.js";
|
||||
import {
|
||||
listJavaScriptRuntimeTargets,
|
||||
observeJavaScriptRuntime,
|
||||
} from "../../../src/application/javascript/JavaScriptRuntimeObservationService.js";
|
||||
import { reconcileJavaScriptRuntimeEvidence } from "../../../src/application/javascript/JavaScriptRuntimeReconciliationService.js";
|
||||
import { CdpBrowserProvider } from "../../../src/browser/CdpBrowserProvider.js";
|
||||
import { V8_INSPECTOR_PROVIDER_IDENTITY } from "../../../src/inspector/providerIdentity.js";
|
||||
import { V8InspectorProvider } from "../../../src/inspector/V8InspectorProvider.js";
|
||||
import { JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE } from "../../../src/contracts/javascript/javascriptRuntimeReconciliationExample.js";
|
||||
@@ -18,10 +20,102 @@ import type {
|
||||
ObserveJavaScriptRuntimeInput,
|
||||
} from "../../../src/domain/javascript/javascriptRuntimeObservation.js";
|
||||
import { observeJavaScriptRuntimeInputSchema } from "../../../src/domain/javascript/javascriptRuntimeObservation.js";
|
||||
import { inspectWebPageInputSchema } from "../../../src/domain/browserObservation.js";
|
||||
import { createEvidence } from "../../../src/domain/evidence.js";
|
||||
import { javascriptRuntimeReconciliationResultSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
|
||||
import { startFakeV8Inspector } from "../../fixtures/inspector/fakeV8Inspector.js";
|
||||
import { startFakeCdpBrowser } from "../../fixtures/fakeCdpBrowser.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
test("reports static-layer Evidence digest failure at its caller path", () => {
|
||||
const layer = JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE.static_layers[0];
|
||||
if (layer === undefined) throw new Error("Expected a static layer example");
|
||||
const runtime = createJavaScriptRuntimeObservationEvidence(
|
||||
"observe_javascript_runtime",
|
||||
{
|
||||
inspector_endpoint: "http://127.0.0.1:9229",
|
||||
target_id: "example-v8-target",
|
||||
runtime_kind: "electron-main",
|
||||
observation_ms: 100,
|
||||
},
|
||||
runtimeObservation("/tmp/index.html", "/tmp/main.js"),
|
||||
V8_INSPECTOR_PROVIDER_IDENTITY,
|
||||
);
|
||||
const result = reconcileJavaScriptRuntimeEvidence({
|
||||
static_layers: [
|
||||
{
|
||||
...layer,
|
||||
analysis: { ...layer.analysis, evidence_id: `ev_${"0".repeat(64)}` },
|
||||
},
|
||||
],
|
||||
runtime_observations: [runtime],
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: {
|
||||
_tag: "AnalysisInputError",
|
||||
issues: [
|
||||
{
|
||||
path: ["static_layers", 0, "analysis", "evidence_id"],
|
||||
reason: "invalid_value",
|
||||
message: "Evidence semantic identifier does not match its record",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("reports browser origin scope mismatch at the caller parameter path", async () => {
|
||||
const browser = await startFakeCdpBrowser();
|
||||
try {
|
||||
const provider = new CdpBrowserProvider();
|
||||
const input = inspectWebPageInputSchema.parse({
|
||||
cdp_endpoint: browser.endpoint,
|
||||
allowed_origins: [browser.allowedOrigin],
|
||||
target_id: "allowed-page",
|
||||
observation_ms: 0,
|
||||
});
|
||||
const observed = await provider.inspectPage(input);
|
||||
if (!observed.ok) throw observed.error;
|
||||
const evidence = createBrowserEvidence(
|
||||
"inspect_web_page",
|
||||
input,
|
||||
observed.value,
|
||||
provider.identity(),
|
||||
);
|
||||
const invalidEvidence = createEvidence(undefined, evidence.provider, {
|
||||
predicateType: evidence.predicate_type,
|
||||
operation: evidence.operation,
|
||||
parameters: { ...evidence.parameters, allowed_origins: [] },
|
||||
result: evidence.normalized_result,
|
||||
confidence: evidence.confidence,
|
||||
authority: evidence.authority,
|
||||
environment: evidence.environment,
|
||||
limitations: evidence.limitations,
|
||||
});
|
||||
const result = reconcileJavaScriptRuntimeEvidence({
|
||||
static_layers: JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE.static_layers,
|
||||
runtime_observations: [invalidEvidence],
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: {
|
||||
_tag: "AnalysisInputError",
|
||||
issues: [
|
||||
{
|
||||
path: ["runtime_observations", 0, "parameters", "allowed_origins"],
|
||||
reason: "invalid_value",
|
||||
message:
|
||||
"Browser Evidence target is outside its recorded origin scope",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
});
|
||||
|
||||
describe("Inspector execution-context lifecycle metadata", () => {
|
||||
test.each([
|
||||
[
|
||||
|
||||
@@ -7,10 +7,21 @@ import { expect, test } from "vitest";
|
||||
import { analyzeJavaScriptApplication } from "../../../src/application/javascript/JavaScriptApplicationService.js";
|
||||
import { createJavaScriptRuntimeObservationEvidence } from "../../../src/application/javascript/JavaScriptRuntimeObservationEvidence.js";
|
||||
import { V8InspectorProvider } from "../../../src/inspector/V8InspectorProvider.js";
|
||||
import { reconcileJavaScriptRuntime } from "../../../src/domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import {
|
||||
parseRuntimeReconciliationInput,
|
||||
reconcileJavaScriptRuntime,
|
||||
} from "../../../src/domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import { reconcileJavaScriptRuntimeInputSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
|
||||
import { startFakeV8Inspector } from "../../fixtures/inspector/fakeV8Inspector.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
const reconcileInput = (input: unknown) =>
|
||||
reconcileJavaScriptRuntime(
|
||||
parseRuntimeReconciliationInput(
|
||||
reconcileJavaScriptRuntimeInputSchema.parse(input),
|
||||
),
|
||||
);
|
||||
|
||||
test("keeps unresolved target identity unknown while matching verified loaded scripts", async () => {
|
||||
const root = await createTestTempDirectory("rea-unresolved-runtime-");
|
||||
const entry = join(root, "entry.js");
|
||||
@@ -37,7 +48,7 @@ test("keeps unresolved target identity unknown while matching verified loaded sc
|
||||
observed.value,
|
||||
provider.identity(),
|
||||
);
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [{ role: "application", analysis: analysis.value }],
|
||||
runtime_observations: [evidence],
|
||||
});
|
||||
|
||||
@@ -9,10 +9,21 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
import { createElectronEvidence } from "../../../src/application/javascript/ElectronEvidence.js";
|
||||
import { analyzeJavaScriptApplication } from "../../../src/application/javascript/JavaScriptApplicationService.js";
|
||||
import { reconcileJavaScriptRuntime } from "../../../src/domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import {
|
||||
parseRuntimeReconciliationInput,
|
||||
reconcileJavaScriptRuntime,
|
||||
} from "../../../src/domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import { reconcileJavaScriptRuntimeInputSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
|
||||
import { inspectElectronPageInputSchema } from "../../../src/domain/javascript/electronObservation.js";
|
||||
import { createWebTextArtifact } from "../../../src/domain/webContentArtifact.js";
|
||||
|
||||
const reconcileInput = (input: unknown) =>
|
||||
reconcileJavaScriptRuntime(
|
||||
parseRuntimeReconciliationInput(
|
||||
reconcileJavaScriptRuntimeInputSchema.parse(input),
|
||||
),
|
||||
);
|
||||
|
||||
const SOURCE = `const worker = new Worker("./worker.js");\nexport const observed = worker;\n`;
|
||||
const execute = promisify(execFile);
|
||||
|
||||
@@ -36,7 +47,7 @@ it("keeps byte-identical cross-layer candidates explicitly ambiguous", async ()
|
||||
writeFile(join(runtime, "app.js"), SOURCE),
|
||||
writeFile(join(runtime, "index.html"), "<script></script>"),
|
||||
]);
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [
|
||||
{
|
||||
role: "application",
|
||||
@@ -82,7 +93,7 @@ it("retains all runtime entities and static load states without projection caps"
|
||||
}),
|
||||
];
|
||||
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [{ role: "application", analysis: staticEvidence }],
|
||||
runtime_observations: runtimeObservations,
|
||||
});
|
||||
@@ -121,7 +132,7 @@ it("rejects runtime source bytes whose Evidence omits source-capture approval",
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
reconcileJavaScriptRuntime({
|
||||
reconcileInput({
|
||||
static_layers: [{ role: "application", analysis: staticEvidence }],
|
||||
runtime_observations: [contradictoryRuntime],
|
||||
}),
|
||||
@@ -131,7 +142,7 @@ it("rejects runtime source bytes whose Evidence omits source-capture approval",
|
||||
it("keeps graph omission counts unknown when a runtime section is unavailable", async () => {
|
||||
const fixture = await applicationFixture();
|
||||
temporary.push(fixture);
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [
|
||||
{ role: "application", analysis: await analyzeFixture(fixture) },
|
||||
],
|
||||
|
||||
@@ -8,20 +8,71 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { createElectronEvidence } from "../../../src/application/javascript/ElectronEvidence.js";
|
||||
import { createElectronActiveEvidence } from "../../../src/application/javascript/ElectronActiveEvidence.js";
|
||||
import { analyzeJavaScriptApplication } from "../../../src/application/javascript/JavaScriptApplicationService.js";
|
||||
import { reconcileJavaScriptRuntime } from "../../../src/domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import { reconcileJavaScriptRuntimeEvidence } from "../../../src/application/javascript/JavaScriptRuntimeReconciliationService.js";
|
||||
import { createEvidence } from "../../../src/domain/evidence.js";
|
||||
import {
|
||||
parseRuntimeReconciliationInput,
|
||||
reconcileJavaScriptRuntime,
|
||||
} from "../../../src/domain/javascript/javascriptRuntimeReconciliation.js";
|
||||
import { reconcileJavaScriptRuntimeInputSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
|
||||
import { javascriptRuntimeReconciliationResultSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
|
||||
import { electronActiveObservationInputSchema } from "../../../src/domain/javascript/electronActiveObservation.js";
|
||||
import { inspectElectronPageInputSchema } from "../../../src/domain/javascript/electronObservation.js";
|
||||
import { createWebTextArtifact } from "../../../src/domain/webContentArtifact.js";
|
||||
import { createElectronActiveObservationFixtureResult } from "../../../src/domain/javascript/electronActiveObservation.fixture.js";
|
||||
|
||||
const reconcileInput = (input: unknown) =>
|
||||
reconcileJavaScriptRuntime(
|
||||
parseRuntimeReconciliationInput(
|
||||
reconcileJavaScriptRuntimeInputSchema.parse(input),
|
||||
),
|
||||
);
|
||||
|
||||
const SOURCE = `const worker = new Worker("./worker.js");\nexport const observed = worker;\n`;
|
||||
|
||||
it("preserves source-capture input paths for runtime Evidence", async () => {
|
||||
const root = await applicationFixture();
|
||||
const application = await analyzeFixture(root);
|
||||
const runtime = electronRuntimeEvidence(root, SOURCE);
|
||||
const invalidRuntime = createEvidence(undefined, runtime.provider, {
|
||||
predicateType: runtime.predicate_type,
|
||||
operation: runtime.operation,
|
||||
parameters: { ...runtime.parameters, include_script_sources: false },
|
||||
result: runtime.normalized_result,
|
||||
confidence: runtime.confidence,
|
||||
authority: runtime.authority,
|
||||
});
|
||||
|
||||
const result = reconcileJavaScriptRuntimeEvidence({
|
||||
static_layers: [{ role: "application", analysis: application }],
|
||||
runtime_observations: [invalidRuntime],
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: {
|
||||
_tag: "AnalysisInputError",
|
||||
issues: [
|
||||
{
|
||||
path: [
|
||||
"runtime_observations",
|
||||
0,
|
||||
"parameters",
|
||||
"include_script_sources",
|
||||
],
|
||||
reason: "invalid_value",
|
||||
message:
|
||||
"Runtime Evidence contains source without source-capture selection",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("reconciles runtime scripts inside dot-prefixed child directories", async () => {
|
||||
const root = await applicationFixture();
|
||||
await mkdir(join(root, "..cache"));
|
||||
await writeFile(join(root, "..cache", "app.js"), SOURCE);
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [
|
||||
{ role: "application", analysis: await analyzeFixture(root) },
|
||||
],
|
||||
@@ -48,7 +99,7 @@ it("matches renderer, frame, script bytes, and worker without claiming execution
|
||||
const staticEvidence = await analyzeFixture(fixture);
|
||||
const runtimeEvidence = electronRuntimeEvidence(fixture, SOURCE);
|
||||
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [{ role: "application", analysis: staticEvidence }],
|
||||
runtime_observations: [runtimeEvidence],
|
||||
});
|
||||
@@ -143,7 +194,7 @@ it("reports a captured digest disagreement instead of accepting a path match", a
|
||||
"export const observed = 'different';\n",
|
||||
);
|
||||
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [{ role: "application", analysis: staticEvidence }],
|
||||
runtime_observations: [runtimeEvidence],
|
||||
});
|
||||
@@ -181,7 +232,7 @@ it("reconciles active Electron as a partial target-only runtime capture", async
|
||||
},
|
||||
);
|
||||
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [{ role: "application", analysis: staticEvidence }],
|
||||
runtime_observations: [runtimeEvidence],
|
||||
});
|
||||
@@ -280,7 +331,7 @@ it("imports an operator-provided cache layer through an explicit file mapping",
|
||||
includeWorker: false,
|
||||
});
|
||||
|
||||
const result = reconcileJavaScriptRuntime({
|
||||
const result = reconcileInput({
|
||||
static_layers: [
|
||||
{ role: "application", analysis: applicationEvidence },
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user