mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
test(javascript): verify endpoint certainty through CLI and MCP
Exercise Map omission, escaped prototypes, opaque eval and candidate Evidence through the rebuilt CLI worker and public MCP transport. Preserve exact static fetch evidence and SQLite certainty controls. Co-authored-by: abdooo2235 <abdalrhmantheiv15@gmail.com>
This commit is contained in:
1 parent
fbfdb6abe9
commit
93196449ad
2 files changed
+166
-1
No files matched your search
@@ -20,6 +20,14 @@ it("reports a candidate endpoint through the worker boundary in the public CLI",
|
||||
import * as vscode from "vscode";
|
||||
client.post("session");
|
||||
(client.get as any)("/api/items");
|
||||
const records = new Map([["/accounts", { name: "Alice" }]]);
|
||||
console.log(records.get("/accounts"));
|
||||
function inspect() {
|
||||
const records = new Map();
|
||||
const alias = records;
|
||||
return alias.get("/local-accounts");
|
||||
}
|
||||
fetch("/network");
|
||||
(new Headers().get as any)("content-type");
|
||||
(new URLSearchParams() as any).delete("q");
|
||||
((vscode.workspace.getConfiguration("editor") as any).get as any)("tabSize");
|
||||
@@ -32,6 +40,33 @@ it("reports a candidate endpoint through the worker boundary in the public CLI",
|
||||
(cache.open as any)("fixture-cache");
|
||||
`,
|
||||
);
|
||||
for (const [name, source] of Object.entries({
|
||||
"escaped.mjs": `const box = {};
|
||||
box.prototype = Map.prototype;
|
||||
function patch(b) { b.prototype.get = fetch; }
|
||||
patch(box); new Map().get("/escaped");`,
|
||||
"returned.mjs":
|
||||
'patch((() => Map.prototype)()); new Map().get("/returned");',
|
||||
"opaque.mjs":
|
||||
'eval("Map.prototype.get = fetch"); new Map().get("/opaque");',
|
||||
"private.mjs":
|
||||
'const box = {}; box.prototype = Map.prototype; new Map().get("/private");',
|
||||
"returned-write.mjs":
|
||||
'const prototype = (() => Map.prototype)(); prototype.get = fetch; new Map().get("/returned-write");',
|
||||
"prototype.mjs":
|
||||
'Object.getPrototypeOf(new Map()).get = fetch; new Map().get("/prototype");',
|
||||
"indirect.mjs":
|
||||
'globalThis.eval("Map.prototype.get = fetch"); new Map().get("/indirect");',
|
||||
"late-link.mjs":
|
||||
'function store() { box.child.prototype = Map.prototype; } const box = {}; const inner = {}; box.child = inner; store(); patch(inner); new Map().get("/late-link");',
|
||||
"constructor.mjs":
|
||||
'new Map().constructor.prototype.get = fetch; new Map().get("/constructor");',
|
||||
"getter.mjs":
|
||||
'const holder = { get prototype() { return Map.prototype; } }; holder.prototype.get = fetch; new Map().get("/getter");',
|
||||
"assignment.mjs":
|
||||
'let run; (run = eval)("Map.prototype.get = fetch"); new Map().get("/assignment");',
|
||||
}))
|
||||
await writeFile(join(root, name), source);
|
||||
const { stdout } = await execute(
|
||||
process.execPath,
|
||||
["scripts/rea.mjs", "analyze-javascript-application", root, "--json"],
|
||||
@@ -49,7 +84,53 @@ it("reports a candidate endpoint through the worker boundary in the public CLI",
|
||||
)
|
||||
.sort(),
|
||||
)
|
||||
.toEqual(["/api/items", "session"]);
|
||||
.toEqual([
|
||||
"/api/items",
|
||||
"/assignment",
|
||||
"/constructor",
|
||||
"/escaped",
|
||||
"/getter",
|
||||
"/indirect",
|
||||
"/late-link",
|
||||
"/network",
|
||||
"/opaque",
|
||||
"/prototype",
|
||||
"/returned",
|
||||
"/returned-write",
|
||||
"session",
|
||||
]);
|
||||
for (const value of [
|
||||
"/api/items",
|
||||
"/assignment",
|
||||
"/constructor",
|
||||
"/escaped",
|
||||
"/getter",
|
||||
"/indirect",
|
||||
"/late-link",
|
||||
"/opaque",
|
||||
"/prototype",
|
||||
"/returned",
|
||||
"/returned-write",
|
||||
]) {
|
||||
const escaped = result.graph.nodes.find(
|
||||
({ kind, observations }) =>
|
||||
kind === "endpoint" &&
|
||||
observations.some(({ properties }) => properties.value === value),
|
||||
);
|
||||
expect(escaped?.observations[0]).toMatchObject({
|
||||
properties: { interpretation: "candidate" },
|
||||
evidence: { state: "inferred", confidence: "low" },
|
||||
});
|
||||
}
|
||||
const request = result.graph.nodes.find(
|
||||
({ kind, observations }) =>
|
||||
kind === "endpoint" &&
|
||||
observations.some(({ properties }) => properties.value === "/network"),
|
||||
);
|
||||
expect(request?.observations[0]?.evidence).toMatchObject({
|
||||
state: "observed",
|
||||
confidence: "exact",
|
||||
});
|
||||
expect(
|
||||
result.graph.nodes
|
||||
.filter(({ kind }) => kind === "storage")
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Client } from "@modelcontextprotocol/client";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import { parseEvidence } from "../../../src/domain/evidence.js";
|
||||
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
it("preserves Map omission and uncertain endpoint Evidence through public MCP", async () => {
|
||||
const root = await createTestTempDirectory("rea-map-endpoint-mcp-");
|
||||
await writeFile(
|
||||
join(root, "app.mjs"),
|
||||
`
|
||||
const records = new Map();
|
||||
const alias = records;
|
||||
alias.get('/accounts');
|
||||
records.delete('/accounts');
|
||||
client.get('/uncertain');
|
||||
fetch('/network');
|
||||
`,
|
||||
);
|
||||
const client = new Client({ name: "map-endpoint-regression", version: "1" });
|
||||
const transport = new StdioClientTransport({
|
||||
command: process.execPath,
|
||||
args: [resolve("scripts/rea.mjs"), "mcp"],
|
||||
cwd: process.cwd(),
|
||||
env: { PATH: process.env.PATH ?? "" },
|
||||
stderr: "pipe",
|
||||
});
|
||||
try {
|
||||
await client.connect(transport);
|
||||
const output = await client.callTool({
|
||||
name: "analyze_javascript_application",
|
||||
arguments: { input_path: root },
|
||||
});
|
||||
expect(output.isError).not.toBe(true);
|
||||
const evidence = parseEvidence(output.structuredContent);
|
||||
const text = output.content.find((block) => block.type === "text");
|
||||
expect(text?.type === "text" ? JSON.parse(text.text) : undefined).toEqual(
|
||||
evidence,
|
||||
);
|
||||
const result = javascriptApplicationAnalysisResultSchema.parse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
const endpoints = result.graph.nodes.filter(
|
||||
({ kind }) => kind === "endpoint",
|
||||
);
|
||||
expect(
|
||||
endpoints
|
||||
.flatMap(({ observations }) =>
|
||||
observations.map(({ properties }) => properties.value),
|
||||
)
|
||||
.sort(),
|
||||
).toEqual(["/network", "/uncertain"]);
|
||||
const candidate = endpoints.find(
|
||||
({ observations }) => observations[0]?.properties.value === "/uncertain",
|
||||
);
|
||||
expect(candidate?.observations[0]).toMatchObject({
|
||||
properties: { interpretation: "candidate" },
|
||||
evidence: {
|
||||
state: "inferred",
|
||||
confidence: "low",
|
||||
limitations: expect.arrayContaining([
|
||||
expect.stringContaining("only a candidate"),
|
||||
]),
|
||||
},
|
||||
});
|
||||
expect(
|
||||
result.graph.edges.find(
|
||||
({ target_node_id }) => target_node_id === candidate?.node_id,
|
||||
)?.evidence,
|
||||
).toMatchObject({ state: "inferred", confidence: "low" });
|
||||
expect(
|
||||
endpoints.find(
|
||||
({ observations }) => observations[0]?.properties.value === "/network",
|
||||
)?.observations[0]?.evidence,
|
||||
).toMatchObject({ state: "observed", confidence: "exact" });
|
||||
} finally {
|
||||
await client.close();
|
||||
await transport.close();
|
||||
}
|
||||
}, 20_000);
|
||||
Reference in new issue
Block a user