mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(inspector): route file locations through URL semantics
This commit is contained in:
1 parent
1a1121c61f
commit
c994870f6b
2 files changed
+132
-1
No files matched your search
@@ -58,7 +58,7 @@ export const authorizeRuntimeLocation = async (
|
||||
asarHeaderAdmission: AsarHeaderAdmission = DEFAULT_ASAR_HEADER_ADMISSION,
|
||||
): Promise<RuntimeLocationDecision> => {
|
||||
throwIfRuntimeObservationCancelled(signal, operation);
|
||||
if (value.startsWith("file:")) {
|
||||
if (URL.parse(value)?.protocol === "file:") {
|
||||
const filePath = await authorizedElectronFile(
|
||||
value,
|
||||
signal,
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { once } from "node:events";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { expect, it, onTestFinished } from "vitest";
|
||||
|
||||
import { toolContract } from "../../../src/contracts/toolContracts.js";
|
||||
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
it("preserves file URL scheme spelling and script identity after real Inspector state changes", async () => {
|
||||
const root = await createTestTempDirectory("rea-inspector-file-url-");
|
||||
const source = join(root, "source #参数%.cjs");
|
||||
const runner = join(root, "runner.cjs");
|
||||
const sourceText = "globalThis.fileUrlProbe = true;\n";
|
||||
await writeFile(source, sourceText);
|
||||
await writeFile(
|
||||
runner,
|
||||
`
|
||||
const { readFileSync } = require("node:fs");
|
||||
const vm = require("node:vm");
|
||||
const scripts = [];
|
||||
process.on("message", (urls) => {
|
||||
for (const filename of urls) {
|
||||
const script = new vm.Script(readFileSync(process.argv[2], "utf8"), { filename });
|
||||
scripts.push(script);
|
||||
script.runInThisContext();
|
||||
}
|
||||
process.send({ loaded: scripts.length });
|
||||
});
|
||||
setInterval(() => {}, 1000);
|
||||
`,
|
||||
);
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
["--inspect=127.0.0.1:0", runner, source],
|
||||
{
|
||||
stdio: ["ignore", "ignore", "pipe", "ipc"],
|
||||
},
|
||||
);
|
||||
onTestFinished(async () => {
|
||||
if (child.exitCode === null && child.signalCode === null) {
|
||||
const exited = once(child, "exit");
|
||||
child.kill("SIGTERM");
|
||||
await exited;
|
||||
}
|
||||
});
|
||||
let stderr = "";
|
||||
if (child.stderr === null) throw new Error("Expected piped Inspector stderr");
|
||||
child.stderr.on("data", (chunk: Buffer) => {
|
||||
stderr += chunk.toString();
|
||||
});
|
||||
const address = /ws:\/\/127\.0\.0\.1:\d+\/[^\s]+/u;
|
||||
await expect.poll(() => stderr, { timeout: 5000 }).toMatch(address);
|
||||
const socket = address.exec(stderr)?.[0];
|
||||
if (socket === undefined) throw new Error("Node omitted its Inspector URL");
|
||||
const endpoint = `http://127.0.0.1:${new URL(socket).port}`;
|
||||
const load = async (urls: readonly string[]) => {
|
||||
const loaded = once(child, "message");
|
||||
child.send(urls);
|
||||
await loaded;
|
||||
};
|
||||
const originalUrl = pathToFileURL(source).href;
|
||||
await load([originalUrl]);
|
||||
const { call } = await connectLocalToolsMcp();
|
||||
const listed = await call("list_javascript_runtime_targets", {
|
||||
inspector_endpoint: endpoint,
|
||||
});
|
||||
expect(listed.isError, JSON.stringify(listed.content)).not.toBe(true);
|
||||
const discovery = toolContract(
|
||||
"list_javascript_runtime_targets",
|
||||
).outputSchema.parse(listed.structuredContent);
|
||||
const targetId = discovery.normalized_result.targets[0]?.target_id;
|
||||
if (targetId === undefined) throw new Error("Node target was not listed");
|
||||
const request = {
|
||||
inspector_endpoint: endpoint,
|
||||
target_id: targetId,
|
||||
observation_ms: 25,
|
||||
};
|
||||
const observe = async () => {
|
||||
const response = await call("observe_javascript_runtime", request);
|
||||
expect(response.isError, JSON.stringify(response.content)).not.toBe(true);
|
||||
return toolContract("observe_javascript_runtime").outputSchema.parse(
|
||||
response.structuredContent,
|
||||
);
|
||||
};
|
||||
const first = await observe();
|
||||
const initialScript = first.normalized_result.scripts.items.find(
|
||||
(script) => script.reported_url === originalUrl,
|
||||
);
|
||||
expect(initialScript).toMatchObject({
|
||||
location: { kind: "file", file_path: source },
|
||||
});
|
||||
|
||||
const addedUrls = [
|
||||
originalUrl.replace(/^file:/u, "FILE:"),
|
||||
`${originalUrl.replace(/^file:/u, "FiLe:")}?instance=2#selected`,
|
||||
` \t${originalUrl}\t `,
|
||||
];
|
||||
await load(addedUrls);
|
||||
const second = await observe();
|
||||
const expectedUrls = [originalUrl, ...addedUrls];
|
||||
const scripts = second.normalized_result.scripts.items.filter((script) =>
|
||||
expectedUrls.includes(script.reported_url ?? ""),
|
||||
);
|
||||
expect(scripts.map((script) => script.reported_url)).toEqual(
|
||||
expect.arrayContaining(expectedUrls),
|
||||
);
|
||||
expect(scripts).toHaveLength(4);
|
||||
expect(new Set(scripts.map((script) => script.script_key)).size).toBe(4);
|
||||
for (const script of scripts)
|
||||
expect(script.location).toEqual({ kind: "file", file_path: source });
|
||||
expect(
|
||||
scripts.find((script) => script.reported_url === originalUrl)?.script_key,
|
||||
).toBe(initialScript?.script_key);
|
||||
|
||||
const retained = await call("get_evidence_bundle", {});
|
||||
expect(retained.isError, JSON.stringify(retained.content)).not.toBe(true);
|
||||
const records = toolContract("get_evidence_bundle").outputSchema.parse(
|
||||
retained.structuredContent,
|
||||
).result.records;
|
||||
const original = records.find(
|
||||
(record) => record.evidence_id === first.evidence_id,
|
||||
);
|
||||
if (original === undefined || !("normalized_result" in original))
|
||||
throw new Error("Original Inspector Evidence was not retained");
|
||||
expect(original.predicate_type).toBe(first.predicate_type);
|
||||
expect(original.normalized_result).toEqual(first.normalized_result);
|
||||
expect(await readFile(source, "utf8")).toBe(sourceText);
|
||||
}, 30_000);
|
||||
Reference in new issue
Block a user