Files
reverse-engineering-anything/src/domain/browserObservation.test.ts
T
morluto b5e98915c6 fix(tools)!: simplify direct invocation and harden boundary contracts (#555)
Remove REA permission grants, scope ceilings, approval confirmations, and inert settings. Preserve selected local evidence, accept caller-chosen commands and paths, and report actual runtime failures.

Harden provider results, schema serialization, snapshot evidence binding, archive paths, source maps, native screenshots, managed EH parsing, and cancellation cleanup. Regenerate tool metadata and document direct invocation.

BREAKING CHANGE: Removed permission configuration and policy commands, approval fields, filesystem scope inputs, and fixed confirmation options. Process capture inherits the host environment and accepts command names; callers must refresh tool schemas and migrate removed fields.
2026-10-05 20:16:44 +08:00

182 lines
6.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
browserEndpointSchema,
browserOriginSchema,
inspectWebPageInputSchema,
isLiteralLoopbackHostname,
listBrowserTargetsInputSchema,
sanitizeEndpointCandidate,
sanitizeBrowserUrl,
} from "./browserObservation.js";
import { captureWebScreenshotInputSchema } from "./webScreenshot.js";
describe("browser observation contracts", () => {
it("normalizes exact HTTP origins without accepting broader URL scopes", () => {
expect(browserOriginSchema.parse("https://Example.COM:443")).toBe(
"https://example.com",
);
expect(browserOriginSchema.parse("http://example.com:80")).toBe(
"http://example.com",
);
for (const value of [
"https://*.example.com",
"https://example.com/path",
"https://example.com/?token=secret",
"https://user:pass@example.com",
"file:///tmp/page.html",
])
expect(browserOriginSchema.safeParse(value).success, value).toBe(false);
});
it("accepts only literal loopback HTTP CDP endpoints", () => {
expect(browserEndpointSchema.parse("http://127.0.0.1:9222")).toBe(
"http://127.0.0.1:9222",
);
expect(browserEndpointSchema.parse("http://[::1]:9222")).toBe(
"http://[::1]:9222",
);
for (const value of [
"http://localhost:9222",
"http://192.168.1.2:9222",
"https://127.0.0.1:9222",
"http://127.0.0.1:9222/json/list",
"http://user:pass@127.0.0.1:9222",
])
expect(browserEndpointSchema.safeParse(value).success, value).toBe(false);
});
it("recognizes bracketed and normalized IPv6 loopback hostnames", () => {
for (const hostname of ["127.0.0.1", "[::1]", "::1"])
expect(isLiteralLoopbackHostname(hostname), hostname).toBe(true);
for (const hostname of ["localhost", "127.0.0.2", "::2"])
expect(isLiteralLoopbackHostname(hostname), hostname).toBe(false);
});
it("applies defaults and rejects unknown public observation input fields", () => {
expect(
listBrowserTargetsInputSchema.parse({
cdp_endpoint: "http://127.0.0.1:9222",
allowed_origins: ["https://app.example.test"],
}),
).toEqual({
cdp_endpoint: "http://127.0.0.1:9222",
allowed_origins: ["https://app.example.test"],
});
expect(
inspectWebPageInputSchema.parse({
cdp_endpoint: "http://127.0.0.1:9222",
allowed_origins: ["https://app.example.test"],
target_id: "page-1",
}),
).toMatchObject({
observation_ms: 500,
include_accessibility_text: false,
include_console_text: false,
include_json_body_shapes: false,
include_websocket_shapes: false,
include_script_sources: false,
include_storage_keys: false,
});
expect(
inspectWebPageInputSchema.safeParse({
cdp_endpoint: "http://127.0.0.1:9222",
allowed_origins: ["https://app.example.test"],
target_id: "page-1",
unknown_field: true,
}).success,
).toBe(false);
});
});
describe("browser observation sensitive surfaces and retention", () => {
it("accepts selected sensitive capture surfaces without extra flags", () => {
const base = {
cdp_endpoint: "http://127.0.0.1:9222",
allowed_origins: ["https://app.example.test"],
target_id: "page-1",
};
for (const input of [
{ include_console_text: true },
{ include_json_body_shapes: true },
{ include_websocket_shapes: true },
])
expect(
inspectWebPageInputSchema.safeParse({ ...base, ...input }).success,
).toBe(true);
expect(
inspectWebPageInputSchema.safeParse({
...base,
include_storage_fingerprints: true,
}).success,
).toBe(false);
});
it("accepts screenshot capture without an extra approval flag", () => {
const input = {
cdp_endpoint: "http://127.0.0.1:9222",
allowed_origins: ["https://app.example.test"],
target_id: "page-1",
};
expect(captureWebScreenshotInputSchema.safeParse(input).success).toBe(true);
});
it("removes only URL userinfo and preserves the original query and fragment", () => {
expect(
sanitizeBrowserUrl(
"https://user:pass@app.example.test/path?token=secret&mode=full&token=again#part",
),
).toEqual({
url: "https://app.example.test/path?token=secret&mode=full&token=again#part",
origin: "https://app.example.test",
query_parameter_names: ["token", "mode", "token"],
redacted: true,
});
const backslashAuthority = String.raw`https:\\user:pass@app.example.test/path?x=a+b&x=two#part`;
const sanitized = sanitizeBrowserUrl(backslashAuthority);
expect(sanitized.url).toBe(
"https://app.example.test/path?x=a+b&x=two#part",
);
expect(sanitized.url).not.toContain("user:pass");
expect(sanitized.redacted).toBe(true);
});
it("retains ordinary query values and malformed URL diagnostics", () => {
const longName = `a${"x".repeat(400)}`;
const parameters = [
`${longName}=secret`,
...Array.from(
{ length: 300 },
(_value, index) => `k${String(index).padStart(3, "0")}=secret`,
),
].join("&");
const sanitized = sanitizeBrowserUrl(
`https://app.example.test/path?${parameters}`,
);
expect(sanitized.query_parameter_names).toHaveLength(301);
expect(sanitized.query_parameter_names).toContain(longName);
expect(sanitized.url).toContain(`${longName}=secret`);
expect(sanitized.url).toContain("k299=secret");
const oversized = sanitizeBrowserUrl(
`https://app.example.test/${"p".repeat(70_000)}`,
);
expect(oversized.origin).toBe("https://app.example.test");
expect(oversized.url.length).toBeGreaterThan(70_000);
expect(oversized.redacted).toBe(false);
const malformed = "https://[invalid?token=diagnostic#fragment";
expect(sanitizeBrowserUrl(malformed)).toEqual({
url: malformed,
origin: null,
query_parameter_names: [],
redacted: false,
});
expect(sanitizeEndpointCandidate(malformed)).toBe(malformed);
expect(sanitizeEndpointCandidate("/api/search?q=rea#results")).toBe(
"/api/search?q=rea#results",
);
});
});