Restore source-position-aware ambient aliases, scalar env/argv reads, candidate endpoint worker data, Chrome DOMSnapshot empty strings, and accumulated Ghidra LaunchSupport diagnostics. Align regression fixtures with declared current contracts, while preserving identity, provenance, cancellation, and cleanup checks. Assert workflow caveats independently at both established locations. Validation: original five source failures reproduced on main; 307 focused tests passed with one platform skip, 22 fixture follow-up tests and 22 workflow/MCP tests passed; full static and docs checks passed. Real public http-server CLI analyses preserve identical artifact identity, statistics, and 581-token selected output. Real Chromium confirms restored DOM form destinations; isolated real service-worker verification passes on main and the change. The complete local browser run retained an unclassified later marker timeout; current-head CI provides complete real-browser and recovery lane results. Native IDA/Ghidra execution and complete local suite execution are not claimed. Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
105 lines
3.7 KiB
TypeScript
105 lines
3.7 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import { join, sep } from "node:path";
|
|
|
|
import { createPackageWithOptions, listPackage } from "@electron/asar";
|
|
import { expect } from "vitest";
|
|
import { z } from "zod";
|
|
|
|
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
cliTest.for(["CLI", "stdio MCP"] as const)(
|
|
"links a block source-map URL containing an asterisk through %s",
|
|
async (surface, { cli }) => {
|
|
const root = await createTestTempDirectory("rea-block-map-");
|
|
const directory = join(root, "input");
|
|
await mkdir(directory);
|
|
const url = "app*part.js.map";
|
|
const directive = "/*# sourceMappingURL=" + url;
|
|
await writeFile(join(directory, "app.js"), directive + "*/");
|
|
await writeFile(
|
|
join(directory, "app_part.js.map"),
|
|
JSON.stringify({ version: 3, sources: [], names: [], mappings: "" }),
|
|
);
|
|
const archive = join(root, "app.asar");
|
|
await createPackageWithOptions(directory, archive, {});
|
|
// ASAR logical names can contain '*' even on Windows. Rename this header
|
|
// key without changing entry bytes, sizes or payload offsets.
|
|
const bytes = await readFile(archive);
|
|
const key = Buffer.from('"app_part.js.map"');
|
|
const offset = bytes.indexOf(key);
|
|
expect(offset).toBeGreaterThan(0);
|
|
expect(bytes.indexOf(key, offset + key.length)).toBe(-1);
|
|
Buffer.from('"' + url + '"').copy(bytes, offset);
|
|
await writeFile(archive, bytes);
|
|
expect(listPackage(archive, { isPack: false })).toContain(sep + url);
|
|
let document: unknown;
|
|
if (surface === "CLI") {
|
|
const result = await cli.run({
|
|
arguments: ["analyze-javascript-application", archive, "--json"],
|
|
});
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
document = result.json;
|
|
} else {
|
|
const { call } = await connectLocalToolsMcp();
|
|
const result = await call("analyze_javascript_application", {
|
|
input_path: archive,
|
|
format: "asar",
|
|
});
|
|
expect(result.isError).not.toBe(true);
|
|
document = result.structuredContent;
|
|
}
|
|
const {
|
|
normalized_result: { graph },
|
|
} = z
|
|
.object({
|
|
normalized_result: javascriptApplicationAnalysisResultSchema,
|
|
})
|
|
.parse(document);
|
|
const digest = createHash("sha256").update(url).digest("hex");
|
|
const map = graph.nodes.find(({ observations }) =>
|
|
observations.some(({ properties }) => properties.declared_url === url),
|
|
);
|
|
expect(
|
|
map,
|
|
"the complete declared URL must identify the map",
|
|
).toBeDefined();
|
|
expect(map?.observations).toContainEqual(
|
|
expect.objectContaining({
|
|
properties: {
|
|
declared_url: url,
|
|
declared_url_sha256: digest,
|
|
resolved_path: url,
|
|
resolution_status: "resolved",
|
|
available: true,
|
|
},
|
|
evidence: expect.objectContaining({
|
|
location: {
|
|
available: true,
|
|
value: {
|
|
kind: "source-range",
|
|
source: "app.js",
|
|
start: { line: 1, column: 0 },
|
|
end: { line: 1, column: directive.length },
|
|
},
|
|
},
|
|
}),
|
|
}),
|
|
);
|
|
expect(graph.edges).toContainEqual(
|
|
expect.objectContaining({
|
|
relation: "maps_to",
|
|
target_node_id: map?.node_id,
|
|
properties: {
|
|
declared_url_sha256: digest,
|
|
resolved_path: url,
|
|
resolution_status: "resolved",
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
);
|