export type TaintSourceType = 'mcp_output' | 'web_fetch' | 'external_file' | 'remote_pull'; export interface TaintSource { type: TaintSourceType; detail: string; at: string; } export interface TaintLedger { sessionId: string; tainted: boolean; sources: TaintSource[]; userPrompts: string[]; createdAt: string; updatedAt: string; } export interface TaintSink { kind: 'network' | 'git_push' | 'git_remote_add' | 'mcp_outbound'; /** External hosts/destinations referenced by the action. */ targets: string[]; detail: string; } export interface TaintFinding { blocked: true; ruleId: string; reason: string; evidence: string; source: TaintSource; sink: TaintSink; } /** * Whether taint tracking is enabled. OPT-IN for now (FCD_TAINT_ENFORCED=1): * the session taint guard held benign commands in invisible approve-once waits * (e.g. a health ping to the org's own API), which reads as a frozen terminal. * Default OFF until it understands trusted destinations and the hold is visible. * FCD_TAINT_DISABLED=1 still force-disables (back-compat). */ export declare function taintEnabled(): boolean; export declare function loadLedger(sessionId: string): TaintLedger; /** Record the developer's prompt text so sink actions can be checked against it. */ export declare function recordUserPrompt(sessionId: string, text: string): void; /** Mark the session as having ingested untrusted content. Reading is never blocked. */ export declare function markTaint(sessionId: string, source: TaintSource): void; type EventKind = 'prompt' | 'shell' | 'mcp' | 'file' | 'read' | 'unknown'; /** Extract hostnames from any URLs / git/scp targets present in a string. */ export declare function extractHosts(text: string): string[]; /** * Classify an event as untrusted INGRESS. Returns the source to record, or * undefined if this event does not ingest untrusted content. */ export declare function classifyIngress(event: EventKind, toolName: string, toolArgs: Record, workspacePath?: string): TaintSource | undefined; /** * Detect whether an event is a SENSITIVE SINK (an action that can exfiltrate or * reach attacker-controlled infrastructure). Returns sink info or undefined. */ export declare function detectSink(event: EventKind, toolName: string, toolArgs: Record): TaintSink | undefined; /** * The deterministic 3-rule check, evaluated against the CURRENT ledger state * (call this BEFORE recording any ingress for the same event): * * block IF session.tainted AND is_sensitive_sink AND NOT user_authorized */ export declare function checkTaintedSink(sessionId: string, event: EventKind, toolName: string, toolArgs: Record): TaintFinding | undefined; /** Record ingress for an event if applicable. Safe to call on every event. */ export declare function noteIngress(sessionId: string, event: EventKind, toolName: string, toolArgs: Record, workspacePath?: string): TaintSource | undefined; export type TaintApprovalStatus = 'pending' | 'approved' | 'denied'; export interface TaintApprovalRequest { id: string; sessionId: string; status: TaintApprovalStatus; event: string; toolName: string; reason: string; /** The exact command/action detail being held (shown to the human, never to the agent). */ detail: string; targets: string[]; createdAt: string; } /** Create a pending approve-once request for a taint finding. Returns undefined on disk errors. */ export declare function createTaintApproval(input: { sessionId: string; event: string; toolName: string; reason: string; detail: string; targets: string[]; }): TaintApprovalRequest | undefined; /** All live pending approve-once requests (expired ones are pruned). */ export declare function listTaintApprovals(): TaintApprovalRequest[]; /** Resolve a pending request (developer's terminal). Returns an outcome message. */ export declare function resolveTaintApproval(id: string, decision: 'approved' | 'denied'): { ok: boolean; message: string; }; /** * Block until the request is approved/denied or the timeout elapses. * ALWAYS consumes (deletes) the request file on exit — the decision applies to * the single held action only and can never be redeemed later. */ export declare function waitForTaintApproval(id: string, timeoutMs: number, pollMs: number): Promise<'approved' | 'denied' | 'timeout'>; /** * Deterministic rule: any agent attempt to run the approve command, or to * read/write the taint state directory (pending IDs / ledger files), is * blocked regardless of taint state. Only a human in their own terminal may * resolve approve-once requests. */ export declare function detectTaintSelfApproval(event: EventKind, toolName: string, toolArgs: Record): { reason: string; } | undefined; export {};