/** * bundle-pin.ts * * SHA-256-pinned bundle distribution. A bundle is fetched from a source * (file / URL / git) and its bytes are verified against an EXPECTED SHA-256 pin * BEFORE the bundle is ever activated. The refusal is hard and structural: * * - a source with no pin → refused (cannot be represented as trusted) * - a source whose bytes mismatch → refused (no "install anyway" path) * * This is the postinstall-checksum lesson made load-bearing: verification is not * an advisory step a caller can skip; `fetchAndVerifyBundle` throws before it * returns bytes unless the pin matches. All three source kinds resolve to the * SAME byte space, so one pin convention (hex SHA-256 of the fetched bytes) * governs every source, no split hash spaces. */ /** A pinned bundle source. `sha256` is REQUIRED, an unpinned source is invalid. */ export interface PinnedBundleSource { readonly kind: 'file' | 'url' | 'git'; /** File path, URL, or git remote (for `git`, combined with `ref`). */ readonly location: string; /** Expected hex SHA-256 of the fetched bytes. Lowercase, 64 hex chars. */ readonly sha256: string; /** Git ref (tag/commit/branch) to archive. Required for `kind: 'git'`. */ readonly ref?: string | undefined; } /** Injectable IO so the fetch path is testable without the network or git. */ export interface BundleFetchDeps { /** Defaults to global `fetch`. */ readonly fetchImpl?: typeof fetch | undefined; /** * Produce deterministic archive bytes for a git source. Defaults to * `git archive --format=tar --remote=`. Injected in tests. */ readonly gitArchive?: ((location: string, ref: string) => Uint8Array) | undefined; } /** Result of comparing fetched bytes to an expected pin. */ export type PinVerification = { readonly ok: true; readonly sha256: string; } | { readonly ok: false; readonly reason: string; readonly expected: string; readonly actual?: string | undefined; }; /** Hex SHA-256 of a byte buffer. */ export declare function computeSha256(bytes: Uint8Array): string; /** * Verify fetched bytes against an expected pin. A missing/malformed pin is a * failure in its own right, the absence of a pin is never "acceptable". */ export declare function verifyBundleBytes(bytes: Uint8Array, expectedSha256: string): PinVerification; /** Raised when a bundle is refused because its pin is missing or mismatched. */ export declare class BundlePinRefusal extends Error { readonly source: PinnedBundleSource; readonly verification: Extract; constructor(source: PinnedBundleSource, verification: Extract); } /** * Fetch a pinned bundle and verify its pin BEFORE returning. Throws * `BundlePinRefusal` on any missing/mismatched pin, there is no path that * yields bytes for an unverified source. */ export declare function fetchAndVerifyBundle(source: PinnedBundleSource, deps?: BundleFetchDeps): Promise<{ readonly bytes: Uint8Array; readonly sha256: string; }>; //# sourceMappingURL=bundle-pin.d.ts.map