/** * `fetch_url`'s transport: curl, with redirects followed here rather than by * curl, so every hop passes the SSRF guard. * * `curl -L` only let us check the URL the model asked for. A public page that * answers `302 Location: http://169.254.169.254/…` (or any LAN/localhost * service) was followed silently and its body handed back to the model — * and `fetch_url` runs without a confirmation prompt. So each hop is resolved, * checked, and the connection pinned to the checked address with `--resolve`, * which also stops a second DNS answer (rebinding) from swapping in a private * address between the check and curl's own lookup. */ export type CurlRunner = (args: string[]) => Promise<{ success: boolean; stdout: string; stderr: string; }>; export type GuardedFetchResult = { ok: true; body: string; finalUrl: string; } | { ok: false; error: string; }; export declare const MAX_FETCH_REDIRECTS = 5; /** One budget for the whole chain — per hop, six slow 302s would hold a tool call for minutes. */ export declare const FETCH_BUDGET_MS = 30000; export declare function fetchUrlGuarded(rawUrl: string, runCurl: CurlRunner, maxRedirects?: number): Promise;