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:
morlutoandShuaixinHuang authored and GitHub committed 2026-11-09 13:21:24 +08:00
1 parent 78a84d75c0
commit b46f4fcebd
112 files changed
+5156 -797

No files matched your search

@@ -1,6 +1,16 @@
import { expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "../../domain/javascript/javascriptStaticAnalysis.js";
import {
analyzeJavaScriptStaticSource,
analyzeParsedJavaScriptStaticSource,
} from "../../domain/javascript/javascriptStaticAnalysis.js";
import { parseJavaScriptSource } from "../../domain/javascript/javascriptSourceParser.js";
const analyzeCommonJsSource = (source: string) => {
const file = parseJavaScriptSource(source, "fixture.cjs");
if (file === null) throw new Error("Expected valid CommonJS fixture");
return analyzeParsedJavaScriptStaticSource(source, file);
};
import {
javaScriptWorkerModuleHeaderSchema,
javaScriptWorkerModuleRecordSchema,
@@ -54,7 +64,7 @@ it("transfers bounded alias selection coverage across the worker boundary", () =
});
it("retains application path change identity and provenance across the worker boundary", () => {
const facts = analyzeJavaScriptStaticSource(`
const facts = analyzeCommonJsSource(`
const { app } = require("electron");
app.setAppPath("./other");
`);
@@ -85,6 +95,61 @@ it("transfers getter expansion limits and unknown bindings across the worker bou
expect(ir.coverage.resourceLimits).toEqual(["getter-expansion"]);
});
it("retains conditional CommonJS provenance and links across the worker boundary", () => {
const ir = analyzeJavaScriptSemantics(
'const { readFile } = require("node:fs");',
);
const binding = ir.bindings.find(({ name }) => name === "readFile");
const link = ir.moduleLinks.find(({ specifier }) => specifier === "node:fs");
expect(binding?.provenance).toMatchObject({
status: "ambiguous",
origins: [{ loaderAuthority: "candidate" }],
});
expect(link).toMatchObject({ loaderAuthority: "candidate" });
expect(
javaScriptWorkerModuleRecordSchema.safeParse({
kind: "binding",
value: {
...binding,
provenance: { ...binding?.provenance, status: "module", reason: null },
},
}).success,
).toBe(false);
for (const record of [
{ kind: "binding", value: binding },
{ kind: "module-link", value: link },
]) {
expect(
javaScriptWorkerModuleRecordSchema.parse(
JSON.parse(JSON.stringify(record)),
),
).toEqual(record);
}
});
it("transfers conditional require requests without claiming a loader", () => {
const facts = analyzeJavaScriptStaticSource(
'require("./dep.cjs"); require.resolve("./config.json");',
);
expect(facts.references).toEqual([
expect.objectContaining({
specifier: "./dep.cjs",
operation: "load",
loader_authority: "candidate",
}),
expect.objectContaining({
specifier: "./config.json",
operation: "resolve",
loader_authority: "candidate",
}),
]);
expect(
javaScriptWorkerStaticAnalysisSchema.parse(
JSON.parse(JSON.stringify(facts)),
),
).toEqual(facts);
});
it("retains candidate endpoint interpretation across the worker boundary", () => {
const facts = analyzeJavaScriptStaticSource(`
client.get("settingKey");
@@ -176,7 +241,7 @@ it("preserves partial request targets through the strict worker schema", () => {
it("preserves scoped IPC receiver provenance and rejects malformed scope metadata", () => {
const facts =
analyzeJavaScriptStaticSource(`const {BrowserWindow} = require("electron");
analyzeCommonJsSource(`const {BrowserWindow} = require("electron");
const window = new BrowserWindow(); window.webContents.mainFrame.ipc.handle("scoped", () => {});`);
expect(facts.electron.ipc).toHaveLength(1);
expect(facts.electron.ipc[0]?.receiver?.kind).toBe("main-frame");
@@ -28,6 +28,10 @@ const findingContext = {
module_runtime: z.string().optional(),
location: range,
};
const electronFindingContext = {
...findingContext,
loader_authority: z.literal("candidate").exactOptional(),
};
const withRuntime = <
Value extends {
module_runtime?: string | undefined;
@@ -78,7 +82,7 @@ const ipcReceiver = z
const ipcChannel = <Shape extends z.ZodRawShape>(shape: Shape) =>
z.union([
z.strictObject({
...findingContext,
...electronFindingContext,
receiver: ipcReceiver,
invocation_location: range.optional(),
resolution_basis: z.literal("wrapper-substitution").optional(),
@@ -87,7 +91,7 @@ const ipcChannel = <Shape extends z.ZodRawShape>(shape: Shape) =>
channel_expression: z.null(),
}),
z.strictObject({
...findingContext,
...electronFindingContext,
receiver: ipcReceiver,
invocation_location: range.optional(),
resolution_basis: z.literal("wrapper-substitution").optional(),
@@ -148,7 +152,7 @@ const ipc = z
};
});
const windowShape = {
...findingContext,
...electronFindingContext,
options_status: z.enum(["object-literal", "dynamic", "missing"]),
web_preferences_status: z.enum(["object-literal", "dynamic", "missing"]),
web_preferences: z.array(
@@ -158,22 +162,26 @@ const windowShape = {
};
const bridgeShape = {
resolution_basis: z.literal("wrapper-substitution").optional(),
...findingContext,
...electronFindingContext,
world: z.enum(["main", "isolated"]),
world_id: staticValue.nullable(),
api_status: z.enum(["object-literal", "dynamic", "missing"]),
members: strings,
unknown_members: count,
};
const utilityShape = { ...findingContext, service_name: z.string().nullable() };
const utilityShape = {
...electronFindingContext,
service_name: z.string().nullable(),
};
const electron = z
.strictObject({
app_path_changes: z
.array(z.strictObject(findingContext).transform(withRuntime))
.array(z.strictObject(electronFindingContext).transform(withRuntime))
.optional(),
call_paths: z
.array(
z.strictObject({
loader_authority: z.literal("candidate").exactOptional(),
entry_kind: z.enum(["bridge-member", "ipc-handler"]),
entry: z.string(),
entry_path: strings.optional(),
@@ -255,7 +263,7 @@ const electron = z
ipc: z.array(ipc),
sender_validations: z.array(
z.strictObject({
...findingContext,
...electronFindingContext,
subject: z.enum([
"sender-url",
"sender-origin",
@@ -291,7 +299,7 @@ const electron = z
),
native_addon_bindings: z.array(
z.strictObject({
...findingContext,
...electronFindingContext,
specifier: z.string(),
binding_kind: z.enum(["import", "require", "re-export"]),
module_kind: z.enum(["import", "require"]),
@@ -303,7 +311,7 @@ const electron = z
protocols: z.array(
z
.strictObject({
...findingContext,
...electronFindingContext,
api: z.string(),
role: z.enum([
"os-default-client",
@@ -327,6 +335,7 @@ const referenceShape = {
...findingContext,
operation: z.enum(["load", "resolve"]),
resolution_base_path: z.string().exactOptional(),
loader_authority: z.literal("candidate").exactOptional(),
// A `factory-loader` specifier is a recovered bundle module key rather than a
// package specifier, so the loader identity travels with the reference.
loader: z
@@ -424,6 +433,7 @@ export const javaScriptWorkerStaticAnalysisSchema = z
z.strictObject({
...findingContext,
role: z.enum(["preload", "renderer"]),
loader_authority: z.literal("candidate").exactOptional(),
path: z.string(),
path_base: z.literal("source-directory").exactOptional(),
resolution_context: pathContext,
@@ -528,20 +538,26 @@ const semanticValue: z.ZodType<JavaScriptSemanticValue> = z.lazy(() =>
);
const origin = z
.strictObject({
loaderAuthority: z.literal("candidate").optional(),
specifier: z.string(),
importedPath: strings,
resolutionMode: z
.enum(["import", "require", "compiler-dependent"])
.optional(),
})
.transform(({ resolutionMode, ...rest }) => ({
.transform(({ resolutionMode, loaderAuthority, ...rest }) => ({
...rest,
...(resolutionMode === undefined ? {} : { resolutionMode }),
...(loaderAuthority === undefined ? {} : { loaderAuthority }),
}));
const provenOrigin = origin.refine(
(value) => value.loaderAuthority !== "candidate",
"Candidate loader authority cannot establish exact module provenance.",
);
const provenance = z.discriminatedUnion("status", [
z.strictObject({
status: z.literal("module"),
origins: z.tuple([origin]),
origins: z.tuple([provenOrigin]),
reason: z.null(),
}),
z.strictObject({
@@ -593,6 +609,7 @@ const coverage = z
});
const moduleLink = z
.strictObject({
loaderAuthority: z.literal("candidate").optional(),
resolutionMode: z
.enum(["import", "require", "compiler-dependent"])
.optional(),
@@ -611,9 +628,10 @@ const moduleLink = z
callableId: z.string().nullable(),
location: range,
})
.transform(({ resolutionMode, ...rest }) => ({
.transform(({ resolutionMode, loaderAuthority, ...rest }) => ({
...rest,
...(resolutionMode === undefined ? {} : { resolutionMode }),
...(loaderAuthority === undefined ? {} : { loaderAuthority }),
}));
const definitionKind = z.enum([
"import",