mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 19:23:24 +00:00
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>
78 lines
2.8 KiB
TypeScript
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);
|
|
},
|
|
);
|