import type { BrowserGrant } from "./browserGrantVerify.js"; export type AuthzDenyCode = "scheme_forbidden" | "browser_internal_page" | "host_forbidden" | "private_network" | "metadata_endpoint" | "port_forbidden" | "dns_rebind" | "origin_not_in_scope" | "effect_not_granted" | "effect_over_ceiling" | "policy_unavailable" | "run_cancelled"; export type AuthzDecision = { allowed: true; } | { allowed: false; code: AuthzDenyCode; message: string; }; export declare const deny: (code: AuthzDenyCode, message: string) => AuthzDecision; /** True when the literal IP is loopback, private, link-local, CGNAT, * unspecified, broadcast, or a metadata address. Conservative: any * parse failure classifies as forbidden (fail closed). */ export declare function isForbiddenIp(ip: string): boolean; export interface ParsedScope { raw: string; scheme: string; wildcardHost: boolean; host: string; port: number; any: boolean; } export declare function parseOriginScope(raw: string): ParsedScope | null; export interface OriginPolicy { scopes: ParsedScope[]; /** true when at least one scope parsed. An EMPTY policy denies all. */ hasScopes: boolean; } export declare function buildOriginPolicy(originScopes: readonly string[]): OriginPolicy; /** Synchronous structural checks: scheme, browser pages, localhost names, * IP-literal private ranges, metadata hosts, origin-scope + port match. * Does NOT resolve DNS — call evaluateUrlResolved for the full gate. */ export declare function evaluateUrlSync(rawUrl: string, policy: OriginPolicy): AuthzDecision; /** Full gate: structural checks PLUS DNS-rebind protection. Every * resolved address for the hostname must be public; one private record * denies the whole navigation. Resolution failure denies (fail closed). * NOTE: a TOCTOU window between this lookup and Chromium's own lookup * remains (documented residual risk); the request-level route handler * re-runs this on every request which keeps the window per-request * rather than per-session. */ export declare function evaluateUrlResolved(rawUrl: string, policy: OriginPolicy): Promise; /** An operation's declared effect must (a) be inside the grant's * actionScopes and (b) not exceed the effect ceiling. Unknown effect * strings deny. */ export declare function checkEffect(effect: string, grant: BrowserGrant): AuthzDecision; type PWBrowserContext = import("playwright").BrowserContext; type PWPage = import("playwright").Page; export interface EnforcementHooks { onViolation: (info: { url: string; code: AuthzDenyCode; message: string; surface: string; }) => void; /** Cancellation flag: when it returns true, everything is denied. */ isCancelled?: () => boolean; } /** Disable WebRTC at the CDP Network domain level in addition to the * init-script layer (belt-and-suspenders). Silently skips if CDP * session creation fails (e.g. attached browser, same-process frame). */ export declare function disableWebRtcViaCdp(cdpSession: unknown): Promise; /** What an enforcement installation hands back so it can be REMOVED again. * * Enforcement used to be install-only, and on an owned browser that was fine: * teardown closes the whole context, handler included. On the ATTACH and * INTERACTIVE paths it was not, because those deliberately leave the user's * browser open after the turn ends. The route handler closed over the run's * registration, `reg.cancelled` went true at teardown and stayed true, and the * handler stayed installed on a page the user was still using — so every * request on that tab, forever after, hit the cancel branch and aborted. * Chrome renders that abort as `(blocked:devtools)`, which reads like a * DevTools or anti-bot problem and is neither. * * Worse, each new run added ANOTHER handler to the same page. The newest one * wins while its run is live, so the symptom only appeared once a run ended: * the tab the agent had touched was bricked, and nothing said why. * * Disposal is idempotent and never throws: a page or context that has already * closed is the normal case at teardown, not an error. */ export interface EnforcementHandle { dispose: () => Promise; } /** Install request-level enforcement on a BrowserContext we OWN (launch * mode). Every document, subresource, XHR, redirect hop, and worker * script fetch flows through here; disallowed ones are aborted. * Downloads are default-denied via the page download handler. * WebSocket connections are intercepted via routeWebSocket (Playwright * 1.48+) with a page-init-script fallback for older builds. * WebRTC is neutralised via an init script on every new page. */ export declare function enforceOnContext(context: PWBrowserContext, policy: OriginPolicy, hooks: EnforcementHooks): Promise; /** Install enforcement on a SINGLE page (attach mode: we never take over * routing for the user's whole externally-owned browser context, only * the leased target the run operates on; navigation of the leased page * and its popups is still fully gated). * WebSocket interception and WebRTC neutralisation are applied to this * page and its popups in the same way as the owned-context path, scoped * to the single leased target. */ export declare function enforceOnPage(page: PWPage, policy: OriginPolicy, hooks: EnforcementHooks): Promise; export {};