/**
 * http-interceptor.ts  --  RawHttpInterceptor (CrabTrap-style)
 *
 * Defense-in-depth governance net that catches arbitrary outbound HTTP calls
 * from AI agents that bypass the official LLM SDK adapters (e.g. a raw
 * `await fetch('https://api.openai.com/...')` call).
 *
 * Inspired by Brex's open-source "CrabTrap" concept but implemented using
 * Node.js built-ins only (no npm dependencies).
 *
 * Key capabilities:
 *   - Patches globalThis.fetch with a governance-aware wrapper.
 *   - Classifies every outbound request before sending.
 *   - Enforces a configurable default policy: 'audit-only' | 'block' | 'sandbox'.
 *   - Detects common secret patterns in request bodies, URLs, and auth headers.
 *   - Writes structured audit events for every interception.
 *   - Never logs raw Authorization / X-API-Key / Bearer token header values.
 *   - attach() / detach() are idempotent.
 *   - getStats() returns runtime interception counts.
 *
 * Limitations (v1):
 *   - Does NOT intercept Node.js `http` / `https` low-level modules (deferred
 *     to a follow-up PR -- see docs/security/http-interceptor.md).
 *   - Does NOT cover non-Node runtimes (Deno, browsers, Bun).
 *   - Does NOT prevent an agent from importing an alternative HTTP client
 *     before attach() is called.  Attach early in process startup.
 *
 * Pen-tests:
 *   PT-CRABTRAP-1  empty packBinding throws UnboundDataError pre-call
 *   PT-CRABTRAP-2  secret in URL query string detected and redacted in audit
 *   PT-CRABTRAP-3  malformed config rejected at construction
 *   PT-CRABTRAP-4  audit entry never contains raw API key from headers
 *
 * @connexum/ai-governance
 */
/**
 * Thrown synchronously before any network call when packBinding is empty.
 * Enforces the Pack-Binding Primacy invariant (AIAG-MEMORY-04).
 */
export declare class UnboundHttpRequestError extends Error {
    readonly code = "UNBOUND_HTTP_REQUEST";
    constructor(url: string);
}
/**
 * Thrown when the interceptor blocks a request due to an unknown host or
 * a detected secret leak.
 */
export declare class HttpRequestBlockedError extends Error {
    readonly code = "HTTP_REQUEST_BLOCKED";
    readonly reason: string;
    constructor(url: string, reason: string);
}
/**
 * Thrown at construction time when the config is invalid.
 */
export declare class HttpInterceptorConfigError extends Error {
    readonly code = "HTTP_INTERCEPTOR_CONFIG_ERROR";
    constructor(message: string);
}
/**
 * Default policy applied to requests that are not on the allow-list.
 *
 *   'audit-only'  -- let the request through but write an audit event.
 *   'block'       -- throw HttpRequestBlockedError before sending.
 *   'sandbox'     -- route to sandboxProxy if configured; falls back to
 *                    'block' if no proxy is configured.
 */
export type DefaultPolicy = 'audit-only' | 'block' | 'sandbox';
/**
 * Policy applied when a secret is detected in the request body, URL, or
 * auth headers.
 *
 *   'block'           -- throw HttpRequestBlockedError before sending.
 *   'redact-and-warn' -- replace the leaked value with [REDACTED] in the
 *                        body and continue; warn via audit event.
 *   'audit-only'      -- let the request through as-is; audit with
 *                        secretLeakDetected: true.
 */
export type SecretLeakPolicy = 'block' | 'redact-and-warn' | 'audit-only';
/** An additional allowed origin registered at runtime. */
export interface AllowedOriginEntry {
    /** Exact hostname or suffix pattern (leading "." = suffix match). */
    host: string;
    /** Human-readable reason for why this host is allowed. */
    reason: string;
    /** When this entry was registered. */
    registeredAt: string;
}
/** Audit event written for every interception. */
export interface HttpInterceptionEvent {
    eventType: 'http:intercepted';
    traceId: string;
    timestamp: string;
    /** Resolved hostname (from URL parse). */
    hostname: string;
    /** HTTP method (GET, POST, ...). */
    method: string;
    /** URL path only -- no query string (query may contain secrets). */
    sanitizedPath: string;
    /** Whether the request URL query string was redacted from audit. */
    queryRedacted: boolean;
    /** Approximate request body size in bytes. */
    bytesOut: number;
    /** HTTP response status code (undefined if request was blocked). */
    responseStatus?: number;
    /** Agent identity string if provided in context. */
    agentIdentity?: string;
    /** Compliance pack bindings in force. */
    packBinding: string[];
    /** Classification outcome. */
    classification: 'allowed' | 'allowed-configured' | 'unknown-host' | 'blocked';
    /** Whether the default policy was applied (vs explicit allow-list match). */
    policyApplied: DefaultPolicy | 'allow-list';
    /** Whether a secret leak was detected in this request. */
    secretLeakDetected: boolean;
    /** Leak finding categories (no raw values). */
    leakCategories?: string[];
    /** Whether the request body was redacted before sending. */
    bodyRedacted?: boolean;
}
/**
 * Per-call context attached to each intercepted fetch call.
 * Callers provide this via the options.__interceptorContext field or by
 * pre-configuring a defaultContext on the interceptor.
 */
export interface HttpInterceptorContext {
    /** Compliance packs that govern this request.  Must be non-empty. */
    packBinding: string[];
    /** Optional agent identity string for audit tagging. */
    agentIdentity?: string;
}
/** Configuration for RawHttpInterceptor. */
export interface RawHttpInterceptorConfig {
    /**
     * Policy for requests to hosts not on the allow-list.
     * Default: 'audit-only'.
     */
    defaultPolicy?: DefaultPolicy;
    /**
     * Policy for requests where a secret is detected.
     * Default: 'block'.
     */
    secretLeakPolicy?: SecretLeakPolicy;
    /**
     * Additional hostnames / suffix patterns to allow beyond the built-in list.
     * Each entry must be a non-empty string.
     */
    additionalAllowedHosts?: string[];
    /**
     * Proxy URL used when defaultPolicy is 'sandbox'.
     * If defaultPolicy is 'sandbox' but this is not set, sandbox falls back
     * to 'block'.
     */
    sandboxProxy?: string;
    /**
     * Default context applied to every request when no per-call context is
     * provided.  If set, packBinding must be non-empty.
     */
    defaultContext?: HttpInterceptorContext;
    /**
     * Audit sink.  Called synchronously after classification, before the
     * upstream fetch is invoked.  If not provided, events are discarded
     * (callers should wire in EventBus or similar).
     */
    onAuditEvent?: (event: HttpInterceptionEvent) => void;
}
/** Runtime statistics returned by getStats(). */
export interface HttpInterceptorStats {
    /** Total fetch calls intercepted since attach(). */
    totalIntercepted: number;
    /** Requests that matched the built-in allow-list. */
    allowListHits: number;
    /** Requests that matched a configured-allow entry. */
    configuredAllowHits: number;
    /** Requests classified as unknown-host. */
    unknownHostHits: number;
    /** Requests blocked (policy=block or secret leak with policy=block). */
    blocked: number;
    /** Secret leaks detected (any policy). */
    secretLeaksDetected: number;
}
/**
 * Governance-aware fetch interceptor.
 *
 * Usage:
 *
 *   const interceptor = new RawHttpInterceptor({
 *     defaultPolicy: 'block',
 *     secretLeakPolicy: 'block',
 *     defaultContext: { packBinding: ['hipaa', 'soc2'] },
 *     onAuditEvent: (evt) => eventBus.publish(evt),
 *   });
 *
 *   interceptor.attach();
 *   // ... all subsequent fetch() calls are now governed ...
 *   interceptor.detach();
 */
export declare class RawHttpInterceptor {
    private readonly cfg;
    /** The original globalThis.fetch before patching. */
    private originalFetch;
    /** Whether the interceptor is currently attached. */
    private attached;
    /** Configured-allow entries registered via addAllowedOrigin(). */
    private readonly configuredAllowList;
    /** Flat list of built-in + additionalAllowedHosts. */
    private readonly builtInHosts;
    /** Secret leak detector instance. */
    private readonly leakDetector;
    /** Runtime statistics. */
    private stats;
    constructor(config?: RawHttpInterceptorConfig);
    /**
     * Patch globalThis.fetch with the governance wrapper.
     * Idempotent: calling attach() when already attached is a no-op.
     */
    attach(): void;
    /**
     * Restore the original globalThis.fetch.
     * Idempotent: calling detach() when not attached is a no-op.
     */
    detach(): void;
    /** Whether the interceptor is currently attached. */
    isAttached(): boolean;
    /**
     * Register an additional allowed origin at runtime.
     *
     * @param host   Exact hostname or ".suffix" pattern.
     * @param reason Human-readable justification (logged in allow-list).
     */
    addAllowedOrigin(host: string, reason: string): void;
    /** Return a copy of the current configured-allow list. */
    getConfiguredAllowList(): readonly AllowedOriginEntry[];
    /** Return a snapshot of runtime statistics. */
    getStats(): Readonly<HttpInterceptorStats>;
    /** Reset statistics counters to zero. */
    resetStats(): void;
    /**
     * Internal interception handler.  Called by the patched globalThis.fetch.
     *
     * Visibility: private -- exposed for testing purposes via _intercept.
     */
    _intercept(input: string | URL | Request, init?: RequestInit & {
        __interceptorContext?: HttpInterceptorContext;
    }): Promise<Response>;
    private _emitAuditEvent;
}
/**
 * Redacts known secret patterns from a body string.
 * Uses the same pattern catalog as SecretLeakDetector.
 *
 * Exposed for testing.
 */
export declare function redactBody(body: string, _patternId: string): string;
/**
 * Create-or-return a process-scoped default interceptor.
 * Useful for applications that want a single shared interceptor.
 */
export declare function getDefaultInterceptor(config?: RawHttpInterceptorConfig): RawHttpInterceptor;
/** Clear the process-scoped default interceptor (useful in tests). */
export declare function clearDefaultInterceptor(): void;
//# sourceMappingURL=http-interceptor.d.ts.map