/** * Endpoint validation for the pluggable LLM layer. * * Trazum lets the caller choose the URL its optional LLM pass talks to. On a * deployed server that is a server-side request forgery primitive: without * this check, anyone who can reach the web app can make it fetch the cloud * metadata service, an internal admin panel, or any host behind the firewall, * and read the response through the error message. * * This lives in the core rather than in the web route on purpose. It is the * most security-sensitive code in the project, so it belongs where it can be * unit-tested and where every caller — the API route today, anything else * later — gets the same answer. */ /** Whether a hostname points somewhere a public service must not fetch. */ export declare function isPrivateHost(hostname: string): boolean; export type EndpointRejection = 'invalid-url' | 'insecure-scheme' | 'private-host' | 'credentials-in-url'; export interface ValidateEndpointOptions { /** * Allow `http:` and private hosts. For local development only — it disables * the entire protection, so it must never be derived from request input. */ allowInsecure?: boolean; } /** * Validates an LLM endpoint URL. Returns `null` when it is safe to fetch, or a * machine-readable reason when it is not. * * A reason code rather than a message so the caller renders it in the reader's * locale, and so a test asserts on the decision rather than on wording. */ export declare function validateLlmEndpoint(raw: string, options?: ValidateEndpointOptions): EndpointRejection | null; /** * Validates an endpoint and returns the value to fetch, with no trailing slash. * * Returning it rather than approving it is the point. The first version of this * validated `baseUrl` and then fetched * `` `${baseUrl.replace(/\/$/, '')}/chat/completions` `` — two different * expressions, so the thing checked was never the thing used, and a later edit * could have moved the check without anything noticing. * * Re-parsing normalises it too: `https://host/v1/../../admin` passes validation * as a string and resolves somewhere else on the wire. * * Every caller in this package that sends a key to a caller-named host goes * through here — both providers and the exact token counter. */ export declare function checkedEndpoint(baseUrl: string, { allowInsecure, name }: ValidateEndpointOptions & { name: string; }): string; /** * `fetch` options that every server-side call in this package must carry. * * `redirect: 'error'` is the one that matters, and it was missing. Everything * above validates the URL the caller named — and then `fetch` followed * redirects by default, so an endpoint that passed every check could answer * `302 Location: http://169.254.169.254/latest/meta-data/` and the request went * there anyway, carrying the `authorization` header. The entire host filter was * one HTTP response away from being bypassed, for the CLI as much as for the * deployed app. * * A refused redirect is a thrown `TypeError`, which is the right outcome: a * legitimate LLM endpoint does not redirect its completions API, and one that * suddenly does is exactly the case worth failing on. */ export declare const SAFE_FETCH_INIT: { readonly redirect: 'error'; readonly credentials: 'omit'; readonly referrerPolicy: 'no-referrer'; }; /** * The endpoints this server will call, from `TRAZUM_ALLOWED_LLM_ENDPOINTS` * (comma-separated). * * An entry that would fail `validateLlmEndpoint` is dropped rather than * honoured. The operator is trusted to choose, not to be immune from pasting * `http://169.254.169.254` into a list that then serves every anonymous caller. * `allowInsecure` is deliberately not offered: an endpoint only reachable with * the protection off has no business being selectable over HTTP. */ export declare function allowedEndpoints(env: Record): readonly string[]; /** * Resolves what a caller asked for to an entry on the list. * * Returns the **listed** value, not the requested one. That distinction is the * entire function: the string from the request is compared and then discarded, * so nothing derived from it reaches `fetch`. */ export declare function resolveEndpoint(requested: string, allowed: readonly string[]): string | null; //# sourceMappingURL=net.d.ts.map