fix(javascript): admit candidate endpoint interpretation in worker output
b58adafa4emits `interpretation: "candidate"` on static endpoint findings, but the worker's strict endpoint schema still rejected the key, so `analyze_javascript_application` failed output validation for any source with a candidate endpoint. Admit the field as an exact optional literal. Update application acceptance and boundary expectations to current main: endpoint identity keys tag literal values (88afcc738), source-map observations and edges carry `resolution_status` (b58adafa4), and a proven Webpack bootstrap reports bundled contextBridge exposures as direct syntax. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
aff46f51fd
commit
0fdac09259
|
|
@ -328,6 +328,7 @@ export const javaScriptWorkerStaticAnalysisSchema = z
|
|||
kind: z.enum(["route", "network"]),
|
||||
value: z.string(),
|
||||
mechanism: z.string(),
|
||||
interpretation: z.literal("candidate").exactOptional(),
|
||||
}),
|
||||
),
|
||||
storage: z.array(
|
||||
|
|
|
|||
|
|
@ -485,6 +485,7 @@ it("preserves complete line-comment source-map URLs through CLI and MCP", async
|
|||
declared_url: declaredUrl,
|
||||
declared_url_sha256: digest,
|
||||
resolved_path: "app.js.map",
|
||||
resolution_status: "resolved",
|
||||
available: true,
|
||||
},
|
||||
evidence: expect.objectContaining({
|
||||
|
|
@ -507,6 +508,7 @@ it("preserves complete line-comment source-map URLs through CLI and MCP", async
|
|||
properties: {
|
||||
declared_url_sha256: digest,
|
||||
resolved_path: "app.js.map",
|
||||
resolution_status: "resolved",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
|
@ -565,6 +567,7 @@ it("resolves source-map URL paths once without changing their declarations", asy
|
|||
declared_url: declaredUrl,
|
||||
declared_url_sha256: digest,
|
||||
resolved_path: path,
|
||||
resolution_status: "resolved",
|
||||
available: true,
|
||||
},
|
||||
evidence: expect.objectContaining({
|
||||
|
|
@ -587,7 +590,11 @@ it("resolves source-map URL paths once without changing their declarations", asy
|
|||
expect.objectContaining({
|
||||
relation: "maps_to",
|
||||
target_node_id: map?.node_id,
|
||||
properties: { declared_url_sha256: digest, resolved_path: path },
|
||||
properties: {
|
||||
declared_url_sha256: digest,
|
||||
resolved_path: path,
|
||||
resolution_status: "resolved",
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
@ -1576,8 +1583,11 @@ it("retains bundled isolated-world contextBridge APIs through dedicated and gene
|
|||
world: "isolated",
|
||||
world_id: { status: "literal", value: 1001, expression: null },
|
||||
api_key: "isolatedApi",
|
||||
api_status: "object-literal",
|
||||
members: ["ping"],
|
||||
resolution_basis: "wrapper-substitution",
|
||||
unknown_members: 0,
|
||||
// The proven Webpack bootstrap resolves `load(2)` directly.
|
||||
resolution_basis: "direct-syntax",
|
||||
}),
|
||||
evidence: expect.objectContaining({
|
||||
location: expect.objectContaining({
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
|
|||
declared_url: url,
|
||||
declared_url_sha256: digest,
|
||||
resolved_path: url,
|
||||
resolution_status: "resolved",
|
||||
available: true,
|
||||
},
|
||||
evidence: expect.objectContaining({
|
||||
|
|
@ -92,7 +93,11 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
|
|||
expect.objectContaining({
|
||||
relation: "maps_to",
|
||||
target_node_id: map?.node_id,
|
||||
properties: { declared_url_sha256: digest, resolved_path: url },
|
||||
properties: {
|
||||
declared_url_sha256: digest,
|
||||
resolved_path: url,
|
||||
resolution_status: "resolved",
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ cliTest(
|
|||
),
|
||||
).toHaveLength(1);
|
||||
expect(repeatedNode.observations).toHaveLength(2);
|
||||
expect(repeatedNode.identity).toMatchObject({ key: "/ok" });
|
||||
expect(repeatedNode.identity).toMatchObject({
|
||||
key: JSON.stringify(["literal", "/ok"]),
|
||||
});
|
||||
expect(
|
||||
repeatedNode.observations.every(({ label }) => label === "/ok"),
|
||||
).toBe(true);
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@ it("retains empty literal evidence across the application boundary surfaces", as
|
|||
);
|
||||
});
|
||||
|
||||
/** Endpoint identity keys tag literal values apart from candidates. */
|
||||
const literalEndpointKey = (value: string): string =>
|
||||
JSON.stringify(["literal", value]);
|
||||
|
||||
it("keeps bridge entry paths stable through worker validation and API seed matching", async () => {
|
||||
const output = await analyzeSource(`
|
||||
const { contextBridge, ipcRenderer } = require("electron");
|
||||
|
|
@ -144,7 +148,7 @@ it("analyzes a plain long-line loader without package metadata", async () => {
|
|||
for (const node of nodes) {
|
||||
expect(node.identity).toMatchObject({
|
||||
strategy: "artifact-local-key",
|
||||
key: "",
|
||||
key: node.kind === "endpoint" ? literalEndpointKey("") : "",
|
||||
});
|
||||
expect(node.observations.map(({ label }) => label)).toEqual([null]);
|
||||
}
|
||||
|
|
@ -165,9 +169,9 @@ it("keeps exact values for empty literals without synthetic application labels",
|
|||
// a literal two-quote endpoint; both keep exact identities.
|
||||
expect(endpoints).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ key: "", labels: [null], values: [""] },
|
||||
{ key: '""', labels: ['""'], values: ['""'] },
|
||||
{ key: "/api", labels: ["/api"], values: ["/api"] },
|
||||
{ key: literalEndpointKey(""), labels: [null], values: [""] },
|
||||
{ key: literalEndpointKey('""'), labels: ['""'], values: ['""'] },
|
||||
{ key: literalEndpointKey("/api"), labels: ["/api"], values: ["/api"] },
|
||||
]),
|
||||
);
|
||||
expect(endpoints).toHaveLength(3);
|
||||
|
|
@ -252,7 +256,7 @@ it("does not match an empty endpoint with a literal two-quote seed", async () =>
|
|||
case_sensitive: true,
|
||||
}).filter(({ node_id: nodeId }) => endpoints.has(nodeId));
|
||||
expect(matches.map(({ node_id: nodeId }) => endpoints.get(nodeId))).toEqual([
|
||||
'""',
|
||||
literalEndpointKey('""'),
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue