Files
rea/src/domain/analysisView/webBundleView.test.ts
T
gensokyo-devandHarsH 6d5532a204 feat(web): page retained bundle endpoint observations and inferences (#7259)
Page retained web-bundle endpoint observations and inferences through shared CLI/MCP projections, preserving source identities, scoped unknowns, coverage and complete Evidence access.

Based on HarsH’s original implementation in #7213 (6b1d5d42). Real Chromium/CLI/SDK verification and whole-task cost limits are recorded in docs/verification/web-bundle-paging-2026-10-26.md.

Explicit user authorization permits leaving human-readiness declarations unchecked and bypassing reproduced main failures (ADB listing fixture, package catalog expectation, untouched APK verifier formatting). No human-review attestation is made.

Co-authored-by: HarsH <[email protected]>
2026-10-27 01:37:39 +08:00

642 lines
17 KiB
TypeScript

import { expect, it } from "vitest";
import type { WebBundleAnalysis } from "../webBundleAnalysis.js";
import { AnalysisInputError } from "../analysisErrorCore.js";
import {
analysisViewRequestSchema,
projectAnalysisView,
type AnalysisViewParent,
} from "./analysisView.js";
const sampleAnalysis = (): WebBundleAnalysis => ({
capture: {
target_url: "https://example.test/app",
target_origin: "https://example.test",
scripts_observed: 3,
scripts_analyzed: 2,
source_artifacts: [],
},
observations: {
chunks: {
nodes: [
{
script_key: "app.js",
url: "https://example.test/app.js",
artifact_sha256: "a".repeat(64),
bytes: 1200,
},
{
script_key: "vendor.js",
url: "https://example.test/vendor.js",
artifact_sha256: "b".repeat(64),
bytes: 4500,
},
],
edges: [],
},
routes: [],
endpoints: [
{
value: "/api/users",
mechanism: "call:fetch",
location: { script_key: "app.js", line: 10, column: 2 },
},
{
value: "/api/users",
mechanism: "call:fetch",
location: { script_key: "vendor.js", line: 42, column: 8 },
},
{
value: "/api/orders",
mechanism: "call:sendBeacon",
location: { script_key: "app.js", line: 85, column: 4 },
},
],
webmcp_declarations: [],
source_maps: {
status: "not_requested",
requested: 0,
processed: 0,
items: [],
},
},
inferences: [
{
kind: "endpoint_candidate",
value: "/api/dynamic-user",
confidence: "low",
basis: [
{
script_key: "app.js",
artifact_sha256: "a".repeat(64),
line: 25,
column: 4,
detector: "call:client.get:unverified-network-receiver",
},
],
},
{
kind: "vendor_fingerprint",
value: "React",
confidence: "high",
basis: [
{
script_key: "vendor.js",
artifact_sha256: "b".repeat(64),
line: 1,
column: 0,
detector: "vendor:react",
},
],
},
],
unknowns: [
{
dimension: "network",
reason: "Unverified client receiver",
affected_script_keys: ["app.js"],
},
],
completeness: {
status: "partial",
parsed_scripts: 2,
parse_failures: 1,
visited_ast_nodes: 150,
},
limitations: ["Script evaluation was omitted"],
});
const makeParent = (
overrides?: Partial<WebBundleAnalysis>,
): AnalysisViewParent => ({
evidenceId: `ev_${"c".repeat(64)}`,
operation: "analyze_web_bundle",
limitations: ["Parent run was bounded"],
normalizedResult: {
...sampleAnalysis(),
...overrides,
},
});
const query = (
source: AnalysisViewParent,
selection: Record<string, unknown>,
) => {
const result = projectAnalysisView(
source,
analysisViewRequestSchema.parse(selection),
);
if (!result.ok) throw result.error;
return result.value;
};
it.each([undefined, null, "https://example.test"])(
"preserves historical omitted and explicit target origins: %s",
(origin) => {
const report = sampleAnalysis();
if (origin === undefined) delete report.capture.target_origin;
else report.capture.target_origin = origin;
const parent = makeParent(report);
for (const selection of [
{ kind: "summary" },
{ kind: "web-bundle", collection: "summary" },
{ kind: "web-bundle", collection: "endpoints", fields: ["value"] },
]) {
const view = query(parent, selection);
if (origin === undefined)
expect(view).not.toHaveProperty("target_origin");
else expect(view).toHaveProperty("target_origin", origin);
if (
view.kind === "summary" ||
(view.kind === "web-bundle" && view.summary !== null)
) {
if (origin === undefined)
expect(view.summary).not.toHaveProperty("target_origin");
else expect(view.summary).toHaveProperty("target_origin", origin);
}
}
},
);
it("counts the distinct full parent/report limitation union before bounding", () => {
const base = makeParent({
limitations: [
"Parent run was bounded",
"Script evaluation was omitted",
"x".repeat(100_000),
],
});
const parent = {
...base,
limitations: [...base.limitations, "Parent-only condition"],
};
for (const selection of [
{ kind: "summary" },
{ kind: "web-bundle", collection: "summary" },
]) {
const view = query(parent, selection);
expect(view).toHaveProperty("summary.limitation_count", 4);
expect(view.limitations).not.toContain("x".repeat(100_000));
expect(view.limitations).toContainEqual(
expect.stringContaining("additional limitations omitted"),
);
}
});
it("retains distinct structured unknown scopes on filtered pages", () => {
const unknowns = [
{
dimension: "parse",
reason: "Source unavailable",
affected_script_keys: ["app.js"],
},
{
dimension: "parse",
reason: "Source unavailable",
affected_script_keys: ["vendor.js"],
},
];
const parent = makeParent({ unknowns });
for (const collection of ["endpoints", "inferences"]) {
const view = query(parent, {
kind: "web-bundle",
collection,
script_keys: ["app.js"],
fields: ["value"],
});
expect(view).toHaveProperty("source_unknowns", unknowns);
expect(view).toHaveProperty("completeness.status", "partial");
}
});
it("pages endpoints and concatenated pages match original records exactly, preserving duplicates", () => {
const parent = makeParent();
const page1 = query(parent, {
kind: "web-bundle",
collection: "endpoints",
offset: 0,
limit: 2,
});
const page2 = query(parent, {
kind: "web-bundle",
collection: "endpoints",
offset: 2,
limit: 2,
});
expect(page1.kind).toBe("web-bundle");
expect(page2.kind).toBe("web-bundle");
if (page1.kind !== "web-bundle" || page2.kind !== "web-bundle") return;
expect(page1.items).toHaveLength(2);
expect(page2.items).toHaveLength(1);
expect(page1.coverage).toMatchObject({
status: "page",
examined: 2,
total: 3,
next_offset: 2,
exhausted: false,
});
expect(page2.coverage).toMatchObject({
status: "page",
examined: 1,
total: 3,
next_offset: null,
exhausted: true,
});
const concatenated = [...page1.items, ...page2.items];
const original = sampleAnalysis().observations.endpoints;
expect(concatenated).toEqual(
original.map((row, source_index) => ({ source_index, ...row })),
);
// Preserves duplicate "/api/users" at different locations
expect(concatenated[0]!.value).toBe("/api/users");
expect(concatenated[1]!.value).toBe("/api/users");
const first = concatenated[0]!;
const second = concatenated[1]!;
if (!("location" in first) || !("location" in second)) {
throw new Error("Expected endpoint rows with location");
}
expect(first.location).not.toEqual(second.location);
});
it("filters endpoints by values, script_keys, mechanisms, and field projections", () => {
const parent = makeParent();
const filtered = query(parent, {
kind: "web-bundle",
collection: "endpoints",
values: ["/api/orders"],
fields: ["value"],
});
if (filtered.kind !== "web-bundle")
throw new Error("Expected web-bundle view");
expect(filtered.items).toEqual([{ source_index: 2, value: "/api/orders" }]);
expect(filtered.coverage.total).toBe(1);
const byScript = query(parent, {
kind: "web-bundle",
collection: "endpoints",
script_keys: ["vendor.js"],
});
if (byScript.kind !== "web-bundle")
throw new Error("Expected web-bundle view");
expect(byScript.items).toHaveLength(1);
const item = byScript.items[0]!;
if (!("location" in item)) {
throw new Error("Expected endpoint row with location");
}
expect(item.location).toMatchObject({ script_key: "vendor.js" });
});
it("pages inference records and filters by kind (endpoint_candidate)", () => {
const parent = makeParent();
const candidatesOnly = query(parent, {
kind: "web-bundle",
collection: "inferences",
kinds: ["endpoint_candidate"],
});
if (candidatesOnly.kind !== "web-bundle")
throw new Error("Expected web-bundle view");
expect(candidatesOnly.items).toHaveLength(1);
expect(candidatesOnly.items[0]).toMatchObject({
kind: "endpoint_candidate",
value: "/api/dynamic-user",
confidence: "low",
});
expect(candidatesOnly.coverage).toMatchObject({
total: 1,
exhausted: true,
});
});
it("preserves partial producer coverage even when view pagination is exhausted", () => {
const parent = makeParent({
completeness: {
status: "partial",
parsed_scripts: 1,
parse_failures: 1,
visited_ast_nodes: 50,
},
});
const page = query(parent, {
kind: "web-bundle",
collection: "endpoints",
offset: 0,
limit: 10,
});
if (page.kind !== "web-bundle") throw new Error("Expected web-bundle view");
expect(page.coverage.exhausted).toBe(true);
// Must remain "partial" and never be upgraded to "complete"
expect(page.completeness.status).toBe("partial");
expect(page.completeness.parse_failures).toBe(1);
});
it("serves web bundle summary via kind: summary and kind: web-bundle collection: summary", () => {
const parent = makeParent();
const summaryView = query(parent, { kind: "summary" });
expect(summaryView.kind).toBe("summary");
if (summaryView.kind === "summary") {
expect(summaryView.summary).toMatchObject({
target_url: "https://example.test/app",
counts: {
endpoints: 3,
inferences: 2,
endpoint_candidates: 1,
},
completeness: { status: "partial" },
});
}
const collectionSummary = query(parent, {
kind: "web-bundle",
collection: "summary",
});
expect(collectionSummary.kind).toBe("web-bundle");
if (collectionSummary.kind === "web-bundle") {
expect(collectionSummary.summary).toMatchObject({
target_url: "https://example.test/app",
counts: {
endpoints: 3,
inferences: 2,
endpoint_candidates: 1,
},
});
}
});
it("returns an empty page when offset is beyond total items", () => {
const parent = makeParent();
const empty = query(parent, {
kind: "web-bundle",
collection: "endpoints",
offset: 100,
limit: 10,
});
if (empty.kind !== "web-bundle") throw new Error("Expected web-bundle view");
expect(empty.items).toEqual([]);
expect(empty.coverage).toMatchObject({
status: "empty",
examined: 0,
total: 3,
next_offset: null,
exhausted: true,
});
});
it("returns typed AnalysisResourceConstraintError when a single record exceeds 1 MiB", () => {
const hugeEndpoint = {
value: "/api/" + "x".repeat(1024 * 1024),
mechanism: "call:fetch",
location: { script_key: "app.js", line: 1, column: 0 },
};
const parent = makeParent({
observations: {
...sampleAnalysis().observations,
endpoints: [hugeEndpoint],
},
});
const result = projectAnalysisView(
parent,
analysisViewRequestSchema.parse({
kind: "web-bundle",
collection: "endpoints",
}),
);
expect(result.ok).toBe(false);
if (result.ok) throw new Error("Expected resource error");
expect(result.error._tag).toBe("AnalysisResourceConstraintError");
expect(result.error.message).toContain("byte budget");
});
it.each([undefined, ["call:fetch"]])(
"counts all matching rows after a byte-limited page: %s",
(mechanisms) => {
const largeRecord = (index: number) => ({
value: `/api/${index}/` + "x".repeat(300_000),
mechanism: "call:fetch",
location: { script_key: "app.js", line: index, column: 0 },
});
const parent = makeParent({
observations: {
...sampleAnalysis().observations,
endpoints: [
largeRecord(1),
largeRecord(2),
largeRecord(3),
largeRecord(4),
],
},
});
const page = query(parent, {
kind: "web-bundle",
collection: "endpoints",
limit: 10,
mechanisms,
});
if (page.kind !== "web-bundle") throw new Error("Expected web-bundle view");
expect(page.byte_limited).toBe(true);
expect(page.items.length).toBeGreaterThan(0);
expect(page.items.length).toBeLessThan(4);
expect(page.coverage.next_offset).toBe(page.items.length);
expect(page.coverage.exhausted).toBe(false);
expect(page.coverage.total).toBe(4);
},
);
it.each(["indices", "values", "script_keys", "mechanisms"])(
"treats an explicit empty %s selector as an empty selection",
(selector) => {
const page = query(makeParent(), {
kind: "web-bundle",
collection: "endpoints",
[selector]: [],
});
expect(page).toHaveProperty("items", []);
expect(page.coverage).toMatchObject({
total: 0,
exhausted: true,
next_offset: null,
});
},
);
it("rejects non-web-bundle parent operation with invalid_value", () => {
const invalidParent: AnalysisViewParent = {
evidenceId: `ev_${"d".repeat(64)}`,
operation: "analyze_javascript_application",
limitations: [],
normalizedResult: sampleAnalysis(),
};
const result = projectAnalysisView(
invalidParent,
analysisViewRequestSchema.parse({
kind: "web-bundle",
collection: "endpoints",
}),
);
expect(result.ok).toBe(false);
if (result.ok) throw new Error("Expected failure");
if (!(result.error instanceof AnalysisInputError)) throw result.error;
expect(result.error.issues[0]!.message).toContain(
"Web-bundle views require analyze_web_bundle",
);
expect(result.error.issues[0]!.reason).toBe("invalid_value");
});
it("continues filtered pages by matching ordinal while preserving original indices", () => {
const report = sampleAnalysis();
const row = report.observations.endpoints[0]!;
const endpoints = [
{ ...row, mechanism: "call:sendBeacon" },
{ ...row, location: { ...row.location, script_key: "vendor.js" } },
row,
{ ...row, value: "/api/orders" },
{ ...row, location: { ...row.location, line: 99 } },
{ ...row, location: { ...row.location, line: 100 } },
{ ...row, location: { ...row.location, script_key: "vendor.js" } },
];
const parent = makeParent({
observations: { ...report.observations, endpoints },
});
const selection = {
kind: "web-bundle",
collection: "endpoints",
script_keys: ["app.js"],
values: ["/api/users"],
mechanisms: ["call:fetch"],
limit: 2,
};
const first = query(parent, selection);
if (first.kind !== "web-bundle") throw new Error("Expected web-bundle page");
expect(first.coverage).toMatchObject({
total: 3,
examined: 2,
next_offset: 2,
exhausted: false,
});
const second = query(parent, {
...selection,
offset: first.coverage.next_offset,
});
if (second.kind !== "web-bundle") throw new Error("Expected web-bundle page");
expect(second.coverage).toMatchObject({
total: 3,
examined: 1,
next_offset: null,
exhausted: true,
});
expect([...first.items, ...second.items]).toEqual(
[2, 4, 5].map((source_index) => ({
source_index,
...endpoints[source_index],
})),
);
});
it("preserves parent artifact identity across summary and page views", () => {
const artifact = { path: "/app.js", sha256: "e".repeat(64) };
const parent: AnalysisViewParent = {
...makeParent(),
artifact,
};
const summary = query(parent, { kind: "summary" });
expect(summary.artifact).toEqual(artifact);
const page = query(parent, {
kind: "web-bundle",
collection: "endpoints",
});
expect(page.artifact).toEqual(artifact);
});
it("filters endpoints by indices and inferences by script_keys and fields", () => {
const parent = makeParent();
const byIndex = query(parent, {
kind: "web-bundle",
collection: "endpoints",
indices: [1],
});
if (byIndex.kind !== "web-bundle")
throw new Error("Expected web-bundle view");
expect(byIndex.items).toHaveLength(1);
expect(byIndex.items[0]).toMatchObject({
value: "/api/users",
location: { script_key: "vendor.js" },
});
const byScriptKey = query(parent, {
kind: "web-bundle",
collection: "inferences",
script_keys: ["vendor.js"],
fields: ["kind", "value"],
});
if (byScriptKey.kind !== "web-bundle")
throw new Error("Expected web-bundle view");
expect(byScriptKey.items).toEqual([
{ source_index: 1, kind: "vendor_fingerprint", value: "React" },
]);
});
it("correctly counts zero findings in summary for an empty web bundle", () => {
const emptyParent = makeParent({
observations: {
chunks: { nodes: [], edges: [] },
routes: [],
endpoints: [],
webmcp_declarations: [],
source_maps: {
status: "not_requested",
requested: 0,
processed: 0,
items: [],
},
},
inferences: [],
});
const summary = query(emptyParent, { kind: "summary" });
if (summary.kind !== "summary") throw new Error("Expected summary");
expect(summary.summary).toMatchObject({
counts: {
endpoints: 0,
inferences: 0,
endpoint_candidates: 0,
chunks: 0,
routes: 0,
},
});
});
it("rejects malformed parent analysis report", () => {
const malformedParent: AnalysisViewParent = {
evidenceId: `ev_${"e".repeat(64)}`,
operation: "analyze_web_bundle",
limitations: [],
normalizedResult: { malformed: true },
};
const result = projectAnalysisView(
malformedParent,
analysisViewRequestSchema.parse({
kind: "web-bundle",
collection: "endpoints",
}),
);
expect(result.ok).toBe(false);
});