/** The extension identity an MCP has committed to, base64 raw 32B each. */ export interface ExtensionPin { identityX25519Pub: string; identityEd25519Pub: string; pinnedAt: number; } /** The identity material an extension hello carries. */ export interface ExtensionIdentityClaim { identityX25519Pub: string; identityEd25519Pub: string; } /** * How the host and peer paths reach the pin. A port rather than a path so the * decision and the storage can be tested apart — and so a caller has to say * what its trust store IS, rather than getting a default that silently writes * into `$HOME` from a unit test. */ export interface ExtensionTrustPort { read(): Promise; write(pin: ExtensionPin): Promise; /** The operator has allowed a new identity to replace the pinned one. */ allowNew: boolean; /** * Where the pin actually lives, for the refusal message. Without it a * refusal can only guess at the default location — and an MCP with an * `identityDir` of its own would tell the user to delete a file that is not * the one blocking them. */ location?: string; } /** The file-backed port: the pin beside the MCP's own identity. */ export declare function fileExtensionTrust(args: { serverName: string; dir?: string; allowNew: boolean; }): ExtensionTrustPort; export type TrustOutcome = /** Nothing pinned yet: accept, and pin once the signature proves the key. */ { decision: 'first-use'; } /** Same identity as last time. */ | { decision: 'pinned'; } /** Different identity, and the operator has not allowed one: refuse. */ | { decision: 'refused'; message: string; } /** Different identity, explicitly allowed: accept and re-pin, loudly. */ | { decision: 'replace'; message: string; }; /** * Environment escape hatch, read only when the caller expressed no opinion. * * An option would be cleaner, and one exists — but the MCPs that construct * `FetchproxyServer` are thirteen separate packages, and an operator whose * extension re-install has just bricked all of them cannot patch thirteen * packages to get out of it. This is the one lever that reaches an * unmodified consumer. */ export declare const TRUST_NEW_EXTENSION_ENV = "FETCHPROXY_TRUST_NEW_EXTENSION"; export declare function allowNewExtensionIdentity(explicit: boolean | undefined, env?: Record): boolean; export declare function decideExtensionTrust(args: { pin: ExtensionPin | null; hello: ExtensionIdentityClaim; allowNew: boolean; serverName: string; /** Where the pin lives; falls back to the default location when unknown. */ location?: string; }): TrustOutcome; /** Where the pin lives — beside the identity, one per MCP. */ export declare function extensionTrustPath(serverName: string, dir?: string): string; export declare function readExtensionPin(serverName: string, dir?: string): Promise; export declare function writeExtensionPin(serverName: string, pin: ExtensionPin, dir?: string): Promise; /** Drop the pin. Returns whether there was one. */ export declare function clearExtensionPin(serverName: string, dir?: string): Promise;