fix(browser): preserve unknown script ownership through reconciliation

This commit is contained in:
morluto committed 2026-10-24 04:23:56 +08:00
1 parent d397ac7427
commit d9a855f5cb
5 files changed
+80 -4

No files matched your search

@@ -144,6 +144,10 @@ Script inventory completeness remains a separate reported fact. Unavailable,
truncated, or attach-limited worker inventory prevents negative code-presence truncated, or attach-limited worker inventory prevents negative code-presence
claims even when the selected page's script inventory is complete. Accepted claims even when the selected page's script inventory is complete. Accepted
positive script correspondences remain loaded. positive script correspondences remain loaded.
An Electron script's explicit unknown `frame_scope` preserves its reported
frame ID and sourceURL provenance as node properties, but does not link that
script to the current frame inventory. Attach-limited script coverage cannot
establish negative code-presence claims.
None of these states proves feature execution, initialization order, None of these states proves feature execution, initialization order,
reachability, or causality. In particular, `not-observed-in-capture` never means reachability, or causality. In particular, `not-observed-in-capture` never means
+3 -3
View File
@@ -4,9 +4,9 @@ import { AnalysisError } from "../../domain/analysisErrorBase.js";
import { AnalysisOutputError } from "../../domain/analysisErrorCore.js"; import { AnalysisOutputError } from "../../domain/analysisErrorCore.js";
import { sanitizeBrowserUrl } from "../../domain/browserObservation.js"; import { sanitizeBrowserUrl } from "../../domain/browserObservation.js";
import { jsonObjectSchema } from "../../domain/jsonValue.js"; import { jsonObjectSchema } from "../../domain/jsonValue.js";
import { import type {
type WebRuntimeSource, WebRuntimeSource,
type webRuntimeLocationSchema, webRuntimeLocationSchema,
} from "../../domain/webRuntime.js"; } from "../../domain/webRuntime.js";
import type { CdpEvent } from "../CdpConnection.js"; import type { CdpEvent } from "../CdpConnection.js";
import type { CdpRuntimeSession } from "./CdpRuntimeSession.js"; import type { CdpRuntimeSession } from "./CdpRuntimeSession.js";
@@ -506,10 +506,12 @@ const assertRuntimeParameters = (
}; };
const scriptsComplete = (completeness: { const scriptsComplete = (completeness: {
readonly attach_limited_sections: readonly string[];
readonly truncated_sections: readonly string[]; readonly truncated_sections: readonly string[];
readonly unavailable_sections: readonly string[]; readonly unavailable_sections: readonly string[];
readonly dropped_events: { readonly scripts: number }; readonly dropped_events: { readonly scripts: number };
}): boolean => }): boolean =>
!completeness.attach_limited_sections.includes("scripts") &&
!completeness.truncated_sections.includes("scripts") && !completeness.truncated_sections.includes("scripts") &&
!completeness.unavailable_sections.includes("scripts") && !completeness.unavailable_sections.includes("scripts") &&
completeness.dropped_events.scripts === 0; completeness.dropped_events.scripts === 0;
@@ -157,7 +157,10 @@ const scriptEntities = (
nodeKind: "runtime-script-instance", nodeKind: "runtime-script-instance",
runtimeKey: script.script_key, runtimeKey: script.script_key,
targetKey: capture.inspection.target.target_id, targetKey: capture.inspection.target.target_id,
frameKey: script.frame_id, frameKey:
"frame_scope" in script && script.frame_scope === "unknown"
? null
: script.frame_id,
scriptKey: script.script_key, scriptKey: script.script_key,
location, location,
staticKind: "javascript", staticKind: "javascript",
@@ -176,6 +179,15 @@ const scriptEntities = (
...("reported_url" in script && script.reported_url !== undefined ...("reported_url" in script && script.reported_url !== undefined
? { reported_url: script.reported_url } ? { reported_url: script.reported_url }
: {}), : {}),
...("frame_scope" in script && script.frame_scope !== undefined
? {
frame_scope: script.frame_scope,
reported_frame_id: script.frame_id,
}
: {}),
...("has_source_url" in script && script.has_source_url !== undefined
? { has_source_url: script.has_source_url }
: {}),
cdp_hash: script.cdp_hash, cdp_hash: script.cdp_hash,
length: script.length, length: script.length,
is_module: script.is_module, is_module: script.is_module,
@@ -11,6 +11,7 @@ import { reconcileJavaScriptRuntimeEvidence } from "../../../../src/application/
import { createEvidence } from "../../../../src/domain/evidence.js"; import { createEvidence } from "../../../../src/domain/evidence.js";
import { mappedRuntimePaths } from "../../../../src/domain/javascript/javascriptRuntimeStaticCandidates.js"; import { mappedRuntimePaths } from "../../../../src/domain/javascript/javascriptRuntimeStaticCandidates.js";
import { projectRuntimeCaptures } from "../../../../src/domain/javascript/javascriptRuntimeReconciliationRuntime.js"; import { projectRuntimeCaptures } from "../../../../src/domain/javascript/javascriptRuntimeReconciliationRuntime.js";
import { parseRuntimeCaptures } from "../../../../src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js";
import { electronPageInspectionSchema } from "../../../../src/domain/javascript/electronObservation.js"; import { electronPageInspectionSchema } from "../../../../src/domain/javascript/electronObservation.js";
import { import {
readRuntimeReconciliationInput, readRuntimeReconciliationInput,
@@ -263,6 +264,63 @@ it("preserves positive script matches without inventing worker absence when work
); );
}); });
it("preserves unknown Electron frame provenance without linking it to an authorized frame", async () => {
const root = await applicationFixture();
const recorded = electronRuntimeEvidence(root, SOURCE);
const inspection = electronPageInspectionSchema.parse(
recorded.normalized_result,
);
const evidence = createEvidence(undefined, recorded.provider, {
predicateType: recorded.predicate_type,
operation: recorded.operation,
parameters: recorded.parameters,
confidence: recorded.confidence,
authority: recorded.authority,
result: {
...inspection,
completeness: {
...inspection.completeness,
status: "attach_limited",
conditions: ["attach_limited"],
attach_limited_sections: ["scripts"],
},
scripts: {
...inspection.scripts,
items: inspection.scripts.items.map((script) => ({
...script,
frame_scope: "unknown",
has_source_url: true,
reported_url: "file:///reported-label.js",
})),
},
},
});
const captures = parseRuntimeCaptures([evidence]);
expect(captures[0]?.scriptsCompleteWithinScope).toBe(false);
const projected = projectRuntimeCaptures(captures);
const script = projected.entities.find(({ kind }) => kind === "script");
expect(script?.frameKey).toBeNull();
expect(script?.node.properties).toMatchObject({
frame_scope: "unknown",
reported_frame_id: inspection.scripts.items[0]?.frame_id,
has_source_url: true,
reported_url: "file:///reported-label.js",
});
const frameIds = new Set(
projected.entities
.filter(({ kind }) => kind === "frame")
.map(({ node }) => node.node_id),
);
expect(
projected.edges.some(
(edge) =>
edge.relation === "contains" &&
frameIds.has(edge.source_node_id) &&
edge.target_node_id === script?.node.node_id,
),
).toBe(false);
});
it("reconciles active Electron as a partial target-only runtime capture", async () => { it("reconciles active Electron as a partial target-only runtime capture", async () => {
const fixture = await applicationFixture(); const fixture = await applicationFixture();
const staticEvidence = await analyzeFixture(fixture); const staticEvidence = await analyzeFixture(fixture);