Resolve stable local constant BrowserWindow options with retained provenance and shared early-exit mutation queries. Preserve source ordering and unknown results for relevant mutations or escapes. Includes real Joplin correctness/cost receipts and regression coverage. Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
110 lines
4.5 KiB
TypeScript
110 lines
4.5 KiB
TypeScript
import { expect } from "vitest";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
|
|
import { writeFixtureFiles } from "../../support/javascriptApplicationFixture.js";
|
|
import { parseEvidence } from "../../../src/domain/evidence.js";
|
|
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
|
|
import { analysisViewResultSchema } from "../../../src/domain/analysisView/analysisView.js";
|
|
|
|
cliTest(
|
|
"retains constant window preferences and inferred source provenance through CLI, MCP and fact views",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-window-options-");
|
|
await writeFixtureFiles(root, {
|
|
"main.js": [
|
|
'throw new Error("Static input must never execute");',
|
|
'const { BrowserWindow } = require("electron");',
|
|
"function open() {",
|
|
' const prefs = {nodeIntegration: true, contextIsolation: false, preload: "./preload.js"};',
|
|
" const options = {webPreferences: prefs};",
|
|
' if (linux) options.icon = "icon.png";',
|
|
" new BrowserWindow(options);",
|
|
" const escaped = {webPreferences: {sandbox: true}};",
|
|
" patch(escaped); new BrowserWindow(escaped);",
|
|
" new BrowserWindow({webPreferences: {sandbox: true}});",
|
|
"}",
|
|
].join("\n"),
|
|
"preload.js": "// Inert preload source",
|
|
});
|
|
const cliResponse = await cli.run({
|
|
arguments: ["analyze-javascript-application", root, "--format", "json"],
|
|
});
|
|
expect(cliResponse.exitCode, JSON.stringify(cliResponse.json)).toBe(0);
|
|
const cliResult = javascriptApplicationAnalysisResultSchema.parse(
|
|
parseEvidence(cliResponse.json).normalized_result,
|
|
);
|
|
const { call } = await connectLocalToolsMcp();
|
|
const response = await call("analyze_javascript_application", {
|
|
input_path: root,
|
|
format: "directory",
|
|
});
|
|
expect(response.isError).not.toBe(true);
|
|
const parent = parseEvidence(response.structuredContent);
|
|
const result = javascriptApplicationAnalysisResultSchema.parse(
|
|
parent.normalized_result,
|
|
);
|
|
expect(result.graph).toEqual(cliResult.graph);
|
|
expect(result.summary).toEqual(cliResult.summary);
|
|
expect(result.summary).toMatchObject({
|
|
browser_windows: 3,
|
|
explicit_web_preferences: 4,
|
|
preload_entrypoints: 1,
|
|
});
|
|
const windows = result.graph.nodes.filter(
|
|
(node) => node.kind === "browser-window",
|
|
);
|
|
const resolved = windows.find(
|
|
(node) =>
|
|
node.observations[0]?.properties.resolution_sources !== undefined,
|
|
);
|
|
expect(resolved?.observations[0]).toMatchObject({
|
|
properties: {
|
|
source_path: "main.js",
|
|
options_status: "object-literal",
|
|
resolution_sources: [
|
|
{ source: "main.js", start: { line: 5 } },
|
|
{ source: "main.js", start: { line: 4 } },
|
|
],
|
|
},
|
|
evidence: {
|
|
state: "inferred",
|
|
authority: "static-relationship-inference",
|
|
location: { value: { source: "main.js", start: { line: 7 } } },
|
|
},
|
|
});
|
|
expect(
|
|
windows.filter(
|
|
(node) =>
|
|
node.observations[0]?.properties.web_preferences_status === "dynamic",
|
|
),
|
|
).toHaveLength(1);
|
|
expect(
|
|
windows.filter(
|
|
(node) => node.observations[0]?.evidence.state === "observed",
|
|
),
|
|
).toHaveLength(2);
|
|
const viewResponse = await call("inspect_analysis_view", {
|
|
source: { kind: "retained-evidence", evidence_id: parent.evidence_id },
|
|
view: {
|
|
kind: "javascript-facts",
|
|
where: { paths: ["main.js"], kinds: ["browser-window"] },
|
|
property_keys: ["web_preferences", "resolution_sources"],
|
|
},
|
|
});
|
|
expect(viewResponse.isError).not.toBe(true);
|
|
const view = analysisViewResultSchema.parse(
|
|
parseEvidence(viewResponse.structuredContent).normalized_result,
|
|
);
|
|
if (view.kind !== "javascript-facts") throw new Error("Expected fact view");
|
|
expect(view.rows).toHaveLength(3);
|
|
const row = view.rows.find((row) => row.node_id === resolved?.node_id);
|
|
expect(row?.evidence).toEqual(resolved?.observations[0]?.evidence);
|
|
expect(row?.properties).toEqual({
|
|
web_preferences: resolved?.observations[0]?.properties.web_preferences,
|
|
resolution_sources:
|
|
resolved?.observations[0]?.properties.resolution_sources,
|
|
});
|
|
},
|
|
);
|