Files
reverse-engineering-anything/tests/boundary/cli/javascriptRejectedEffects.test.ts
T
44d359bd05 fix(javascript): omit effects refused by host construction (#11122)
Filter child-process, fetch/WebSocket and TLS effects for literal calls
the host refuses to construct. Share copied child options across validation
and projection, preserving uncertainty from own and inherited getters.
Includes the original implementations from #10528, #10529 and #10530.

Validation: 394 domain/public CLI/MCP tests, then 54 request/public tests after the
review correction, static checks and discovery passed. Also verified 29
Node 24.22.1 probes and actual Chromium 156 header/Request constructors.
Full browser app/network behavior was not tested. Analysis does not execute
target source.

Fixes #10522
Fixes #10523
Fixes #10524
Related: #10528, #10529, #10530

Co-authored-by: RRFZ <247457381+Plastic-time@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-11-15 21:05:27 +08:00

78 lines
2.8 KiB
TypeScript

import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { toolContract } from "../../../src/contracts/toolContracts.js";
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
const report = (value: unknown) =>
javascriptApplicationAnalysisResultSchema.parse(
toolContract("analyze_javascript_application").outputSchema.parse(value)
.normalized_result,
);
cliTest(
"keeps only possible host effects through CLI and MCP",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-js-rejected-effects-");
const path = join(root, "main.mjs");
const source = `import { spawn } from "node:child_process";
import tls from "node:tls";
export function rejected(url) {
spawn("");
fetch(url, { method: "CONNECT" });
fetch(url, { headers: { "a b": "1" } });
new WebSocket("wss://example.test/ws#fragment");
tls.connect({ port: 443, secureProtocol: "bogus" });
}
export function possible(url) {
spawn("node");
fetch(url, { method: "PATCH" });
new WebSocket("wss://example.test/ws");
tls.connect({ port: 443, secureProtocol: "TLS_method" });
spawn("node", [], { get a() { this.detached = true; return 0; }, detached: 1 });
fetch(url, { get cache() { delete this.method; return "default"; }, method: "CONNECT" });
fetch(url, { headers: { get x() { delete this["a b"]; return "1"; }, "a b": "1" } });
}
`;
await writeFile(path, source);
const result = await cli.run({
arguments: [
"analyze-javascript-application",
root,
"--detail",
"complete",
"--json",
],
});
expect(result.exitCode, result.stderr).toBe(0);
const analysis = report(result.json);
const methods = (kind: string) =>
analysis.semantic_graph.nodes
.filter((node) => node.kind === kind)
.map((node) => node.properties.method)
.sort();
expect(methods("child-process")).toEqual(["spawn", "spawn"]);
expect(methods("request")).toEqual([
"WebSocket",
"fetch",
"fetch",
"fetch",
]);
expect(methods("resource")).toEqual(["connect"]);
const { call } = await connectLocalToolsMcp();
const mcp = await call("analyze_javascript_application", {
input_path: root,
detail: "complete",
});
expect(mcp.isError, JSON.stringify(mcp)).not.toBe(true);
expect(report(mcp.structuredContent).semantic_graph).toEqual(
analysis.semantic_graph,
);
expect(await readFile(path, "utf8")).toBe(source);
},
);