Files
rea/src/domain/analysisView/webNetworkCaptureView.test.ts
T
gensokyo-dev 4e716b0607 perf(analysis-view): reuse validated immutable captures (#5349)
Reuse the format owner's full validation for exact authenticated immutable captures across retained queries. Preserve ordinary mutable-input validation and per-request subject, coverage and budget checks.

Refs #3133.

Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-20 03:32:18 +00:00

884 lines
25 KiB
TypeScript

import { expect, it } from "vitest";
import { createHash } from "node:crypto";
import { createEvidence } from "../evidence.js";
import { freezeJsonSnapshot } from "../immutableJson.js";
import { webNetworkCaptureSchema } from "../webNetworkCapture.js";
import { projectAnalysisView } from "./analysisView.js";
const capture = () => {
const body = Buffer.from("original body");
const artifact = {
path: "/recordings/input.saz",
sha256: "b".repeat(64),
bytes: 100,
};
const decoder = { id: "fixture", name: "Fixture", version: "1" };
const report = webNetworkCaptureSchema.parse({
artifact,
decoder,
format: "saz",
runtime_attribution: "unknown",
limitations: [],
container: {
reported: { members: [] },
numeric_literals: [],
redactions: [],
records_pointer: null,
},
total_records: 9,
records: [7, 2].map((ordinal) => ({
ordinal,
location: { kind: "archive-members", members: [`raw/${ordinal}_c.txt`] },
reported: {
session_id: String(ordinal),
time: null,
request: {
method: "POST",
url: "https://example.invalid/a",
body: body.toString(),
},
},
binary_fields: [
{
pointer: "/request/body",
representation: "producer-bytes",
state: "retained",
content_base64: body.toString("base64"),
bytes: body.length,
sha256: createHash("sha256").update(body).digest("hex"),
},
],
numeric_literals: [
{
pointer: "/time",
producer_type: "json-number",
literal: "9007199254740993",
},
],
redactions: [],
limitations: [],
})),
});
const evidence = createEvidence({ ...artifact, format: "file" }, decoder, {
operation: "inspect_web_network_capture",
parameters: { record_ordinals: [7, 2] },
result: report,
confidence: "observed",
authority: "historical-reference",
});
return {
report,
parent: {
evidenceId: evidence.evidence_id,
operation: evidence.operation,
normalizedResult: report,
subject: evidence.subject,
limitations: evidence.limitations,
},
};
};
it("checks each parent's subject even after its immutable capture has been validated", () => {
const { parent } = capture();
const source = {
...parent,
normalizedResult: freezeJsonSnapshot(parent.normalizedResult),
};
expect(projectAnalysisView(source, { kind: "summary" }).ok).toBe(true);
expect(
projectAnalysisView({ ...source, subject: null }, { kind: "summary" }).ok,
).toBe(false);
if (source.subject === null) throw new Error("Expected fixture subject");
expect(
projectAnalysisView(
{
...source,
subject: { ...source.subject, local_path: "/different.saz" },
},
{ kind: "summary" },
).ok,
).toBe(false);
expect(projectAnalysisView(source, { kind: "summary" }).ok).toBe(true);
});
it("keeps selected-record page coverage distinct from capture coverage and unsafe number absence", () => {
const { parent, report } = capture();
const summary = projectAnalysisView(parent, { kind: "summary" });
expect(summary.ok && summary.value).toMatchObject({
summary: { total_records: 9, retained_records: 2 },
coverage: { examined: 2, total: 2 },
});
const preview = projectAnalysisView(parent, {
kind: "capture",
detail: "preview",
offset: 0,
limit: 1,
});
expect(preview.ok && preview.value).toMatchObject({
items: [
{
ordinal: 7,
reported: { time: null },
numeric_literals: [{ pointer: "/time", literal: "9007199254740993" }],
},
],
coverage: { total: 2, examined: 1, next_offset: 1, exhausted: false },
});
expect(JSON.stringify(preview)).not.toContain("original body");
expect(JSON.stringify(preview)).not.toContain("content_base64");
const complete = projectAnalysisView(parent, {
kind: "capture",
detail: "complete",
offset: 1,
limit: 1,
});
expect(complete.ok && complete.value).toMatchObject({
items: [report.records[1]],
coverage: { total: 2, examined: 1, next_offset: null, exhausted: true },
});
const empty = projectAnalysisView(parent, {
kind: "capture",
detail: "preview",
offset: 50,
limit: 1,
});
expect(empty.ok && empty.value).toMatchObject({
items: [],
coverage: {
status: "empty",
total: 2,
examined: 0,
next_offset: null,
exhausted: true,
},
});
});
it("retains explicitly unknown digests and rejects a different subject path", () => {
const { parent, report } = capture();
const unknown = projectAnalysisView(
{
...parent,
subject: null,
normalizedResult: {
...report,
artifact: { ...report.artifact, sha256: null },
},
},
{ kind: "summary" },
);
expect(unknown.ok && unknown.value).toMatchObject({
artifact: { sha256: null },
});
expect(unknown.ok && unknown.value.unknowns.join(" ")).toContain(
"excluded artifact digest",
);
if (parent.subject === null) throw new Error("Expected fixture subject");
const mismatched = projectAnalysisView(
{
...parent,
subject: { ...parent.subject, local_path: "/different/source.saz" },
},
{ kind: "summary" },
);
expect(mismatched.ok).toBe(false);
});
it("rejects invalid ordinal coverage in a borrowed parent", () => {
const { parent, report } = capture();
const result = projectAnalysisView(
{
...parent,
normalizedResult: {
...report,
records: [report.records[0], report.records[0]],
},
},
{ kind: "summary" },
);
expect(result.ok).toBe(false);
});
const nativePreview = (
format: "mitmproxy" | "har",
request: Readonly<Record<string, unknown>>,
{
response = {
http_version: "HTTP/1.1",
status_code: 404,
reason: "Not Found",
content: "omitted body",
},
producerType = "integer",
sidecars,
flowType = "http",
redactions = [],
binaryFields = [],
}: {
readonly response?: Readonly<Record<string, unknown>>;
readonly producerType?: "integer" | "float";
readonly flowType?: string | null;
readonly binaryFields?: readonly Record<string, unknown>[];
readonly redactions?: readonly {
pointer: string;
reason: string;
scope?: string;
}[];
readonly sidecars?: readonly {
pointer: string;
producer_type: string;
literal: string;
}[];
} = {},
) => {
// The bridge records a numeric sidecar for every native number.
const literals =
sidecars ??
Object.entries({ request, response }).flatMap(([side, fields]) =>
Object.entries(fields)
.filter(([, value]) => typeof value === "number")
.map(([field, value]) => ({
pointer: `/${side}/${field}`,
producer_type: producerType,
literal: String(value),
})),
);
const artifact = {
path: "/recordings/flows.mitm",
sha256: "c".repeat(64),
bytes: 100,
};
const decoder = { id: "fixture", name: "Fixture", version: "1" };
const report = webNetworkCaptureSchema.parse({
artifact,
decoder,
format,
runtime_attribution: "unknown",
limitations: [],
container: {
reported: null,
numeric_literals: [],
redactions: [],
records_pointer: null,
},
total_records: 1,
records: [
{
ordinal: 0,
location: { kind: "byte-range", offset: 0, bytes: 10 },
reported: {
...(flowType === null ? {} : { type: flowType }),
request: { ...request, headers: [["Accept", "*/*"]] },
response,
},
binary_fields: binaryFields,
numeric_literals: literals,
redactions,
limitations: [],
},
],
});
const evidence = createEvidence({ ...artifact, format: "file" }, decoder, {
operation: "inspect_web_network_capture",
parameters: {},
result: report,
confidence: "observed",
authority: "historical-reference",
});
const preview = projectAnalysisView(
{
evidenceId: evidence.evidence_id,
operation: evidence.operation,
normalizedResult: report,
subject: evidence.subject,
limitations: evidence.limitations,
},
{ kind: "capture", detail: "preview", offset: 0, limit: 1 },
);
if (!preview.ok || preview.value.kind !== "capture")
throw new Error("Expected a capture preview page.");
return preview.value;
};
it("previews the mitmproxy request target and status code as headline fields", () => {
const preview = nativePreview("mitmproxy", {
host: "example.test",
port: 443,
method: "GET",
scheme: "https",
authority: "",
path: "/users/42",
http_version: "HTTP/1.1",
});
expect(preview).toMatchObject({
items: [
{
reported: {
type: "http",
request: {
method: "GET",
scheme: "https",
host: "example.test",
port: 443,
authority: "",
path: "/users/42",
http_version: "HTTP/1.1",
},
response: {
http_version: "HTTP/1.1",
status_code: 404,
reason: "Not Found",
},
},
numeric_literals: [
{
pointer: "/request/port",
producer_type: "integer",
literal: "443",
},
{
pointer: "/response/status_code",
producer_type: "integer",
literal: "404",
},
],
},
],
});
expect(JSON.stringify(preview)).not.toContain("Accept");
expect(JSON.stringify(preview)).not.toContain("omitted body");
});
it("previews the asterisk-form OPTIONS target", () => {
expect(
nativePreview("mitmproxy", { method: "OPTIONS", path: "*" }).items[0]
?.reported,
).toMatchObject({ request: { method: "OPTIONS", path: "*" } });
});
it.each([
[
"an ambiguous absolute path",
"mitmproxy",
"https:user:password@example.test/a",
],
["a network-path reference", "mitmproxy", "//user:password@example.test/a"],
[
"a slash-backslash reference",
"mitmproxy",
"/\\user:password@example.test/a",
],
[
"a slash-backslash reference with an unparseable port",
"mitmproxy",
"/\\user:password@example.test:65536/a",
],
["a path with an at-sign", "mitmproxy", "/users/password@example"],
["a slash-tab reference", "mitmproxy", "/\t/user:password@example.test/a"],
["an oversized path", "mitmproxy", `/${"password".repeat(1024)}`],
["a nested path value", "mitmproxy", { content: "password ".repeat(64) }],
["a path in a non-mitmproxy record", "har", "/users/password"],
] as const)("keeps %s out of the preview", (_label, format, path) => {
const preview = nativePreview(format, { method: "GET", path });
const [item] = preview.items;
expect(item?.reported).toMatchObject({ request: { method: "GET" } });
expect(JSON.stringify(item?.reported)).not.toContain("password");
if (format === "har")
expect(JSON.stringify(item?.reported)).not.toContain("status_code");
});
it("bounds the serialized mitmproxy headline of each preview record", () => {
const control = "\u0001".repeat(8 * 1024);
const malformed = nativePreview("mitmproxy", {
method: "GET",
scheme: control,
host: control,
port: control,
authority: control,
path: `/${control}`,
});
expect(malformed.items[0]?.reported).toMatchObject({
request: { method: "GET" },
});
expect(
Buffer.byteLength(JSON.stringify(malformed.items[0]?.reported)),
).toBeLessThan(1024);
const escaped = nativePreview("mitmproxy", {
method: "GET",
path: `/${'"'.repeat(2 * 1024 - 1)}`,
});
expect(escaped.items[0]?.reported).toMatchObject({
request: { path: `/${'"'.repeat(2 * 1024 - 1)}` },
});
expect(
Buffer.byteLength(JSON.stringify(escaped.items[0]?.reported)),
).toBeLessThan(5 * 1024);
});
it("keeps producer floats out of integer mitmproxy headline slots", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", port: 443, path: "/a" },
{
response: {
http_version: "HTTP/1.1",
status_code: 404,
reason: "Not Found",
},
producerType: "float",
},
).items[0]?.reported;
expect(reported).toMatchObject({
request: { method: "GET", path: "/a" },
response: { reason: "Not Found" },
});
expect(reported).not.toMatchObject({ request: { port: 443 } });
expect(reported).not.toMatchObject({ response: { status_code: 404 } });
});
it.each([
[
"an oversized literal",
[
{
pointer: "/request/port",
producer_type: "integer",
literal: "4".repeat(100_000),
},
],
],
[
"a literal that does not represent the value",
[{ pointer: "/request/port", producer_type: "integer", literal: "444" }],
],
[
"duplicate sidecars",
[
{ pointer: "/request/port", producer_type: "integer", literal: "443" },
{ pointer: "/request/port", producer_type: "integer", literal: "443" },
],
],
])(
"keeps a port whose sidecar has %s out of the preview",
(_label, sidecars) => {
const [item] = nativePreview(
"mitmproxy",
{ method: "GET", port: 443, path: "/a" },
{ response: { http_version: "HTTP/1.1", reason: "OK" }, sidecars },
).items;
expect(item?.reported).toEqual({
type: "http",
request: { method: "GET", path: "/a" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
expect(item?.numeric_literals).toEqual([]);
},
);
it.each(["tcp", null])(
"adds no mitmproxy headline fields to a %s flow",
(flowType) => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a", port: 443 },
{ flowType },
).items[0]?.reported;
expect(reported).toEqual({
...(flowType === null ? {} : { type: flowType }),
request: { method: "GET" },
response: { http_version: "HTTP/1.1", reason: "Not Found" },
});
},
);
it("keeps a string target that carries a numeric sidecar out of the preview", () => {
const [item] = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
sidecars: [
{
pointer: "/request/path",
producer_type: "integer",
literal: "9".repeat(100_000),
},
],
},
).items;
expect(item?.reported).toEqual({
type: "http",
request: { method: "GET" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
expect(item?.numeric_literals).toEqual([]);
});
it("keeps a mitmproxy headline the record marks as redacted out of the preview", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", host: "secret", path: "/a" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
redactions: [
{ pointer: "/request/host", reason: "explicit-sensitive-value" },
],
},
).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: { method: "GET", path: "/a" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
});
it("rejects a non-number integer headline without throwing", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a", port: { toString: null } },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
sidecars: [
{ pointer: "/request/port", producer_type: "integer", literal: "443" },
],
},
).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: { method: "GET", path: "/a" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
});
it.each([
["the request", "/request", { method: "GET" }],
["the record root", "", {}],
] as const)(
"keeps mitmproxy headlines under a redacted %s out of the preview",
(_label, pointer, request) => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", host: "secret", path: "/secret" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
redactions: [{ pointer, reason: "explicit-sensitive-value" }],
},
).items[0]?.reported;
expect(JSON.stringify(reported)).not.toContain("secret");
expect(reported).toMatchObject({ request });
},
);
it("keeps a mitmproxy headline with a redacted byte descriptor out of the preview", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", host: "example.test", path: "/secret" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
binaryFields: [
{
pointer: "/request/path",
representation: "producer-bytes",
state: "redacted",
content_base64: null,
bytes: null,
sha256: null,
},
],
},
).items[0]?.reported;
expect(reported).toMatchObject({
request: { method: "GET", host: "example.test" },
});
expect(JSON.stringify(reported)).not.toContain("secret");
});
it("adds no mitmproxy headline fields when the flow type is redacted", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
redactions: [{ pointer: "/type", reason: "explicit-sensitive-value" }],
},
).items[0]?.reported;
expect(reported).toMatchObject({ request: { method: "GET" } });
expect(reported).not.toMatchObject({ request: { path: "/a" } });
});
it.each([
["the flow type", "/type"],
["the record root", ""],
])(
"adds no mitmproxy headline fields when %s carries a numeric sidecar",
(_label, pointer) => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
sidecars: [{ pointer, producer_type: "integer", literal: "1" }],
},
).items[0]?.reported;
expect(reported).toMatchObject({ request: { method: "GET" } });
expect(reported).not.toMatchObject({ request: { path: "/a" } });
},
);
const retainedBytes = (pointer: string, text: string) => {
const bytes = Buffer.from(text);
return {
pointer,
representation: "producer-bytes",
state: "retained",
content_base64: bytes.toString("base64"),
bytes: bytes.length,
sha256: createHash("sha256").update(bytes).digest("hex"),
};
};
it("adds no mitmproxy headline fields when the flow type was producer bytes", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
binaryFields: [retainedBytes("/type", "http")],
},
).items[0]?.reported;
expect(reported).toMatchObject({ type: "http", request: { method: "GET" } });
expect(reported).not.toMatchObject({ request: { path: "/a" } });
});
it("keeps mitmproxy headlines under a byte-valued side out of the preview", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a", port: 443 },
{
response: { http_version: "HTTP/1.1", reason: "OK", status_code: 200 },
binaryFields: [
retainedBytes("/request", "GET /a"),
retainedBytes("/response", "200"),
],
},
).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: { method: "GET" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
});
it("previews a byte-backed path but not a byte-backed port", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a", port: 443 },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
binaryFields: [
retainedBytes("/request/path", "/a"),
retainedBytes("/request/port", "443"),
],
},
).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: { method: "GET", path: "/a" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
});
it("adds no mitmproxy headline fields when the flow type has a child facet", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
sidecars: [
{ pointer: "/type/child", producer_type: "integer", literal: "1" },
],
},
).items[0]?.reported;
expect(reported).toMatchObject({ request: { method: "GET" } });
expect(reported).not.toMatchObject({ request: { path: "/a" } });
});
it.each([
[
"a child sidecar",
{
sidecars: [
{ pointer: "/request/path/0", producer_type: "integer", literal: "1" },
],
},
],
[
"a child redaction",
{
redactions: [
{ pointer: "/request/path/0", reason: "explicit-sensitive-value" },
],
},
],
[
"HAR content bytes",
{
binaryFields: [
{
...retainedBytes("/request/path", "/a"),
representation: "har-base64-content",
},
],
},
],
[
"bytes that are not its text",
{ binaryFields: [retainedBytes("/request/path", "/b")] },
],
[
"a byte count that is not its text",
{ binaryFields: [{ ...retainedBytes("/request/path", "/a"), bytes: 3 }] },
],
[
"a digest that is not its text",
{
binaryFields: [
{ ...retainedBytes("/request/path", "/a"), sha256: "0".repeat(64) },
],
},
],
] as const)(
"keeps a mitmproxy path with %s out of the preview",
(_label, facets) => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", host: "example.test", path: "/a" },
{ response: { http_version: "HTTP/1.1", reason: "OK" }, ...facets },
).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: { method: "GET", host: "example.test" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
},
);
it.each([
["path", { method: "GET", path: "/\ud800" }, { method: "GET" }],
[
"host",
{ method: "GET", host: "a\udc00.test", path: "/a" },
{ method: "GET", path: "/a" },
],
])(
"keeps a mitmproxy %s with an unpaired surrogate out of the preview",
(_field, request, expected) => {
const reported = nativePreview("mitmproxy", request, {
response: { http_version: "HTTP/1.1", reason: "OK" },
}).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: expected,
response: { http_version: "HTTP/1.1", reason: "OK" },
});
},
);
it("keeps an unpaired-surrogate path out despite replacement-character bytes", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/\ud800" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
binaryFields: [retainedBytes("/request/path", "/�")],
},
).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: { method: "GET" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
});
it("keeps mitmproxy headlines under a numeric sidecar out of the preview", () => {
const [item] = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a", port: 443 },
{
response: { http_version: "HTTP/1.1", reason: "OK", status_code: 200 },
sidecars: [
{ pointer: "/request", producer_type: "integer", literal: "7" },
{ pointer: "/request/port", producer_type: "integer", literal: "443" },
{
pointer: "/response/status_code",
producer_type: "integer",
literal: "200",
},
],
},
).items;
expect(item?.reported).toEqual({
type: "http",
request: { method: "GET" },
response: { http_version: "HTTP/1.1", reason: "OK", status_code: 200 },
});
expect(item?.numeric_literals).toEqual([
{
pointer: "/response/status_code",
producer_type: "integer",
literal: "200",
},
]);
});
it("keeps sibling mitmproxy headlines next to an omitted property name", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", host: "example.test", path: "/a" },
{
response: { http_version: "HTTP/1.1", reason: "OK" },
redactions: [
{
pointer: "/request",
reason: "explicit-sensitive-value",
scope: "property-name",
},
],
},
).items[0]?.reported;
expect(reported).toMatchObject({
request: { method: "GET", host: "example.test", path: "/a" },
});
});
it("selects mitmproxy target fields from the request and the status from the response only", () => {
const reported = nativePreview(
"mitmproxy",
{ method: "GET", path: "/a", status_code: 200 },
{
response: { http_version: "HTTP/1.1", reason: "OK", path: "/extension" },
},
).items[0]?.reported;
expect(reported).toEqual({
type: "http",
request: { method: "GET", path: "/a" },
response: { http_version: "HTTP/1.1", reason: "OK" },
});
});
it.each(["scheme", "host", "port", "authority"])(
"keeps a userinfo-bearing mitmproxy %s out of the preview",
(field) => {
const preview = nativePreview("mitmproxy", {
method: "GET",
path: "/users/42",
[field]: "user:password@example.test",
});
const reported = preview.items[0]?.reported;
expect(reported).toMatchObject({
request: { method: "GET", path: "/users/42" },
});
expect(JSON.stringify(reported)).not.toContain("password");
},
);