mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
fix(javascript): preserve loader authority for exact suffixes (#9477)
* fix(javascript): require exact loader suffix case * fix(javascript): share exact loader mode across import resolution * test(process): align symlink fixture with filesystem checkpoints * test(javascript): normalize the module resolution oracle path separators * test(frida): assert the CLI spawn Evidence contract * test(mcp): use an unsupported analysis-view parent * test(browser): separate source-location line bounds from parity * fix(javascript): preserve uncertain loader provenance * test(javascript): cover uncertain require resolution * fix(javascript): retain conditional Electron evidence * fix(javascript): preserve timed semantic provenance * fix(javascript): retain conditional builtin effects * test(javascript): distinguish bundled host authority * fix(javascript): preserve nested loader invocation identity * test(javascript): qualify Electron fixture authority * fix(javascript): preserve loader invocation authority * fix(javascript): respect source order for resolver escapes * fix(javascript): check nested loader callable mutations * fix(javascript): retain conditional constructor requests * fix(reference): retain constructor loader relationships * fix(reference): follow nested loader callable paths * refactor(javascript): share callable mutation interpretation * fix(javascript): require exact package loader suffixes * refactor(javascript): unify conditional relation evidence * refactor(javascript): unify conditional node evidence * fix(javascript): retain unknown authority for mixed case sources * fix(javascript): preserve loader uncertainty for dotfiles * fix(reference): classify javascript suffix dotfiles * test(reference): cover suffix dotfiles through cli * fix(javascript): retain equivalent conditional built-in origins * fix(javascript): preserve wrapped resolver operation * fix(javascript): retain nested conditional built-in receivers * test(javascript): declare CommonJS in native addon fixtures * fix(javascript): retain wrapped resolver candidates * style: format merged native command schema * fix(javascript): preserve uncertain loader authority * test(javascript): require candidate preload evidence * test(javascript): cover reference loader member writes --------- Co-authored-by: ShuaixinHuang <1836656514@qq.com>
This commit is contained in:
1 parent
78a84d75c0
commit
b46f4fcebd
112 files changed
+5156
-797
No files matched your search
@@ -0,0 +1,200 @@
|
||||
import { expect, it } from "vitest";
|
||||
import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";
|
||||
import { analyzeCommonJsSemanticFixture } from "../../../tests/fixtures/javascriptCommonJsAnalysis.js";
|
||||
|
||||
const source = `const {spawn} = require('child_process');
|
||||
const timers = require('timers');
|
||||
const child = spawn('tool', []); child.kill();
|
||||
const timer = timers.setTimeout(() => {}, 1); timers.clearTimeout(timer);`;
|
||||
|
||||
it("retains conditional child and timer observations without proving a loader", () => {
|
||||
const result = analyzeJavaScriptSemantics(source);
|
||||
expect(result.childProcessSpawns).toMatchObject([
|
||||
{ command: "tool", builtinAuthority: "candidate" },
|
||||
]);
|
||||
expect(result.childProcessInteractions).toMatchObject([
|
||||
{ kind: "signal", builtinAuthority: "candidate", resolution: "partial" },
|
||||
]);
|
||||
expect(result.timerOperations).toMatchObject([
|
||||
{ kind: "schedule", builtinAuthority: "candidate" },
|
||||
{ kind: "cancel", builtinAuthority: "candidate" },
|
||||
]);
|
||||
const proven = analyzeCommonJsSemanticFixture(source);
|
||||
expect(proven.childProcessSpawns[0]).not.toHaveProperty("builtinAuthority");
|
||||
expect(proven.timerOperations[0]).not.toHaveProperty("builtinAuthority");
|
||||
});
|
||||
|
||||
it("does not treat shadowed or overwritten bindings as candidate builtins", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
const cp = require('child_process'); cp.spawn = custom; cp.spawn('bad', []);
|
||||
function local(require) { require('timers').setTimeout(() => {}, 1); }
|
||||
`);
|
||||
expect(result.childProcessSpawns).toEqual([]);
|
||||
expect(result.timerOperations).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not promote a builtin binding read before initialization", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
spawn('early', []);
|
||||
var { spawn } = require('child_process');
|
||||
spawn('late', []);
|
||||
`);
|
||||
expect(result.childProcessSpawns).toMatchObject([
|
||||
{ command: "late", builtinAuthority: "candidate" },
|
||||
]);
|
||||
expect(result.childProcessSpawns).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("tracks conditional builtin slot writes without discarding unrelated or previously captured methods", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
const saved = require('child_process').spawn;
|
||||
require('child_process').exec = custom;
|
||||
require('child_process').spawn('unrelated', []);
|
||||
require('child_process').spawn = custom;
|
||||
require('child_process').spawn('replaced', []);
|
||||
saved('captured', []);
|
||||
`);
|
||||
expect(
|
||||
result.childProcessSpawns.map(({ command, builtinAuthority }) => ({
|
||||
command,
|
||||
builtinAuthority,
|
||||
})),
|
||||
).toEqual([
|
||||
{ command: "unrelated", builtinAuthority: "candidate" },
|
||||
{ command: "captured", builtinAuthority: "candidate" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("retains a global process read conditionally when a candidate module may have changed it", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
require('process').env.MODE = custom;
|
||||
const mode = process.env.MODE;
|
||||
`);
|
||||
expect(result.configurationOperations).toMatchObject([
|
||||
{ key: "MODE", builtinAuthority: "candidate" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not turn a proven same-slot replacement into a conditional global process read", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
process.env.MODE = custom;
|
||||
const mode = process.env.MODE;
|
||||
`);
|
||||
expect(result.configurationOperations).toEqual([]);
|
||||
});
|
||||
|
||||
it("weakens default-import builtin effects after a conditional same-slot write", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
import fs from 'fs';
|
||||
require('fs').readFileSync = custom;
|
||||
fs.readFileSync('config.json');
|
||||
`);
|
||||
expect(result.configurationOperations).toMatchObject([
|
||||
{ key: "config.json", builtinAuthority: "candidate" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps named builtin snapshots proven while weakening mutable default namespaces", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
import {readFileSync} from 'fs';
|
||||
import http from 'http'; import timers from 'timers'; import cp from 'child_process';
|
||||
require('fs').readFileSync = custom;
|
||||
require('http').get = custom;
|
||||
require('timers').setTimeout = custom;
|
||||
require('child_process').spawn = custom;
|
||||
readFileSync('named.json'); http.get('http://example.test');
|
||||
timers.setTimeout(() => {}, 1); cp.spawn('tool', []);
|
||||
`);
|
||||
expect(result.configurationOperations).toMatchObject([{ key: "named.json" }]);
|
||||
expect(result.configurationOperations[0]).not.toHaveProperty(
|
||||
"builtinAuthority",
|
||||
);
|
||||
expect(result.requestOperations).toMatchObject([
|
||||
{ builtinAuthority: "candidate" },
|
||||
]);
|
||||
expect(result.timerOperations).toMatchObject([
|
||||
{ builtinAuthority: "candidate" },
|
||||
]);
|
||||
expect(result.childProcessSpawns).toMatchObject([
|
||||
{ builtinAuthority: "candidate" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps namespace snapshot methods proven while marking the mutable default object conditional", () => {
|
||||
const result = analyzeJavaScriptSemantics(`
|
||||
import * as fs from 'fs';
|
||||
require('fs').readFileSync = custom;
|
||||
fs.readFileSync('snapshot.json');
|
||||
fs.default.readFileSync('mutable.json');
|
||||
`);
|
||||
const snapshot = result.configurationOperations.find(
|
||||
({ key }) => key === "snapshot.json",
|
||||
);
|
||||
const mutable = result.configurationOperations.find(
|
||||
({ key }) => key === "mutable.json",
|
||||
);
|
||||
expect(snapshot).toBeDefined();
|
||||
expect(snapshot).not.toHaveProperty("builtinAuthority");
|
||||
expect(mutable).toMatchObject({ builtinAuthority: "candidate" });
|
||||
});
|
||||
|
||||
it("preserves namespace process env snapshot across object replacement, but not nested mutation", () => {
|
||||
const replaced = analyzeJavaScriptSemantics(`
|
||||
import * as p from 'process'; require('process').env = custom; p.env.MODE;
|
||||
`).configurationOperations.find(({ key }) => key === "MODE");
|
||||
expect(replaced).toBeDefined();
|
||||
expect(replaced).not.toHaveProperty("builtinAuthority");
|
||||
const mutated = analyzeJavaScriptSemantics(`
|
||||
import * as p from 'process'; require('process').env.MODE = custom; p.env.MODE;
|
||||
`).configurationOperations.find(({ key }) => key === "MODE");
|
||||
expect(mutated).toMatchObject({ builtinAuthority: "candidate" });
|
||||
});
|
||||
|
||||
it("distinguishes proven namespace object replacement from proven slot mutation", () => {
|
||||
const replaced = analyzeJavaScriptSemantics(`
|
||||
import * as p from 'process'; process.env = custom; p.env.MODE;
|
||||
`).configurationOperations.find(({ key }) => key === "MODE");
|
||||
expect(replaced).toBeDefined();
|
||||
expect(replaced).not.toHaveProperty("builtinAuthority");
|
||||
const mutated = analyzeJavaScriptSemantics(`
|
||||
import * as p from 'process'; process.env.MODE = custom; p.env.MODE;
|
||||
`).configurationOperations.find(({ key }) => key === "MODE");
|
||||
expect(mutated).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps function fingerprints partial when built-in effects depend on an unknown loader", () => {
|
||||
const source = `const { spawn } = require('child_process'); function execute() { spawn('tool', []); } function unrelated() { return 1; }`;
|
||||
const candidate = analyzeJavaScriptSemantics(source);
|
||||
const proven = analyzeCommonJsSemanticFixture(source);
|
||||
const fingerprint = (result: typeof candidate, name: string) => {
|
||||
const callable = result.callables.find((item) => item.name === name);
|
||||
return result.functionFingerprints.find(
|
||||
(item) => item.callableId === callable?.callableId,
|
||||
);
|
||||
};
|
||||
expect(fingerprint(candidate, "execute")).toMatchObject({
|
||||
status: "partial",
|
||||
components: { effects: ["child-process"] },
|
||||
});
|
||||
expect(fingerprint(candidate, "execute")?.limitations.length).toBeGreaterThan(
|
||||
1,
|
||||
);
|
||||
expect(fingerprint(candidate, "unrelated")?.status).toBe("complete");
|
||||
expect(fingerprint(proven, "execute")?.status).toBe("complete");
|
||||
});
|
||||
|
||||
it("marks an ESM fingerprint partial only when a conditional write affects its builtin effect", () => {
|
||||
const sample = (write: string) =>
|
||||
analyzeJavaScriptSemantics(`
|
||||
import http from 'http';
|
||||
${write}
|
||||
function request() { http.get('http://example.test'); }
|
||||
`).functionFingerprints[0];
|
||||
expect(sample("")?.status).toBe("complete");
|
||||
const conditional = sample("require('http').get = custom;");
|
||||
expect(conditional).toMatchObject({
|
||||
status: "partial",
|
||||
components: { effects: ["network"] },
|
||||
});
|
||||
expect(conditional?.limitations.length).toBeGreaterThan(1);
|
||||
});
|
||||
Reference in new issue
Block a user