mirror of
https://github.com/morluto/rea
synced 2026-10-27 22:45:19 -04:00
0bc2b42001
Keep malformed or missing CDP opcodes and payload facts unknown, retain observed zero and empty payloads, and avoid false capture differences while preserving independently known facts. Validation: 59 source tests; compiled public CLI and stdio MCP fake-CDP acceptance; check:fast; docs:check; changed-file formatting. Real Chromium malformed-event behavior was not tested. BREAKING CHANGE: WebSocket event opcode is nullable and numeric values are restricted to the four-bit protocol range. Fixes #5666
183 lines
4.2 KiB
TypeScript
183 lines
4.2 KiB
TypeScript
import { expect, it } from "vitest";
|
|
|
|
import { inspectWebPageInputSchema } from "../domain/browserObservation.js";
|
|
import { webPageInspectionSchema } from "../domain/browserObservationSchemas.js";
|
|
import { CdpCaptureEvents } from "./CdpCaptureEvents.js";
|
|
|
|
const origin = "https://example.test";
|
|
|
|
const createEvents = (): CdpCaptureEvents =>
|
|
new CdpCaptureEvents(
|
|
inspectWebPageInputSchema.parse({
|
|
cdp_endpoint: "http://127.0.0.1:9222",
|
|
allowed_origins: [origin],
|
|
target_id: "page",
|
|
include_websocket_shapes: true,
|
|
}),
|
|
new Set([origin]),
|
|
);
|
|
|
|
const captureFrame = (
|
|
opcode: unknown,
|
|
payloadData: unknown,
|
|
includeOpcode = true,
|
|
includePayload = true,
|
|
) => {
|
|
const events = createEvents();
|
|
events.ingest({
|
|
method: "Network.webSocketCreated",
|
|
params: { requestId: "socket", url: "wss://example.test/live" },
|
|
});
|
|
events.ingest({
|
|
method: "Network.webSocketFrameReceived",
|
|
params: {
|
|
requestId: "socket",
|
|
response: {
|
|
...(includeOpcode ? { opcode } : {}),
|
|
...(includePayload ? { payloadData } : {}),
|
|
},
|
|
},
|
|
});
|
|
return {
|
|
events,
|
|
frame: events.webSocketConnectionsById.get("socket")?.events[0],
|
|
};
|
|
};
|
|
|
|
it.each([
|
|
{
|
|
label: "missing",
|
|
opcode: undefined,
|
|
payload: "",
|
|
hasOpcode: false,
|
|
hasPayload: true,
|
|
},
|
|
{
|
|
label: "wrong type",
|
|
opcode: "1",
|
|
payload: "text",
|
|
hasOpcode: true,
|
|
hasPayload: true,
|
|
},
|
|
{
|
|
label: "explicit null",
|
|
opcode: null,
|
|
payload: "",
|
|
hasOpcode: true,
|
|
hasPayload: true,
|
|
},
|
|
{
|
|
label: "negative",
|
|
opcode: -1,
|
|
payload: "",
|
|
hasOpcode: true,
|
|
hasPayload: true,
|
|
},
|
|
{
|
|
label: "fractional",
|
|
opcode: 1.5,
|
|
payload: "text",
|
|
hasOpcode: true,
|
|
hasPayload: true,
|
|
},
|
|
{
|
|
label: "above opcode width",
|
|
opcode: 16,
|
|
payload: "",
|
|
hasOpcode: true,
|
|
hasPayload: true,
|
|
},
|
|
{
|
|
label: "non-finite",
|
|
opcode: Number.NaN,
|
|
payload: "",
|
|
hasOpcode: true,
|
|
hasPayload: true,
|
|
},
|
|
] as const)(
|
|
"keeps $label WebSocket opcode unknown",
|
|
({ opcode, payload, hasOpcode, hasPayload }) => {
|
|
const { events, frame } = captureFrame(
|
|
opcode,
|
|
payload,
|
|
hasOpcode,
|
|
hasPayload,
|
|
);
|
|
expect(frame).toEqual({
|
|
direction: "received",
|
|
opcode: null,
|
|
payload_bytes: null,
|
|
payload_shape: null,
|
|
});
|
|
expect(events.completeness.snapshot().excluded).toContainEqual({
|
|
section: "websocket_frames",
|
|
reason: "invalid_protocol_value",
|
|
count: 1,
|
|
});
|
|
expect(
|
|
webPageInspectionSchema.shape.network.shape.websocket_connections.element.safeParse(
|
|
{
|
|
request_id: "socket",
|
|
url: "wss://example.test/live",
|
|
events: [frame],
|
|
},
|
|
).success,
|
|
).toBe(true);
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
{ label: "continuation", opcode: 0, payload: "", bytes: 0, format: "binary" },
|
|
{ label: "empty text", opcode: 1, payload: "", bytes: 0, format: "text" },
|
|
{
|
|
label: "reserved four-bit opcode",
|
|
opcode: 15,
|
|
payload: "",
|
|
bytes: 0,
|
|
format: "binary",
|
|
},
|
|
] as const)(
|
|
"preserves observed $label data",
|
|
({ opcode, payload, bytes, format }) => {
|
|
const { events, frame } = captureFrame(opcode, payload);
|
|
expect(frame).toEqual({
|
|
direction: "received",
|
|
opcode,
|
|
payload_bytes: bytes,
|
|
payload_shape: { format, json_shape: null },
|
|
});
|
|
expect(events.completeness.snapshot().excluded).not.toContainEqual(
|
|
expect.objectContaining({
|
|
section: "websocket_frames",
|
|
reason: "invalid_protocol_value",
|
|
}),
|
|
);
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
{
|
|
label: "missing payload",
|
|
opcode: 1,
|
|
payload: undefined,
|
|
hasPayload: false,
|
|
},
|
|
{ label: "wrong-type payload", opcode: 1, payload: 42, hasPayload: true },
|
|
] as const)(
|
|
"does not fabricate an empty payload for $label",
|
|
({ opcode, payload, hasPayload }) => {
|
|
const { events, frame } = captureFrame(opcode, payload, true, hasPayload);
|
|
expect(frame).toEqual({
|
|
direction: "received",
|
|
opcode,
|
|
payload_bytes: null,
|
|
payload_shape: null,
|
|
});
|
|
expect(events.completeness.snapshot().excluded).toContainEqual({
|
|
section: "websocket_frames",
|
|
reason: "invalid_protocol_value",
|
|
count: 1,
|
|
});
|
|
},
|
|
);
|