import { describe, expect, it, vi } from "vitest"; import type { BackendIssuedImageAsset, ImageCapabilityVerifier, ImagePresetReference, ImageProbeRequest, PublicImmutableImageAsset, } from "../../src/application/ports/browser-transfer/image-cdn.ts"; import { createBrowserImageProbe, type ImageProbeScheduler, } from "../../src/adapters/browser-transfer/image-cdn/browser-image-probe.ts"; import { IMAGE_CDN_IMPLEMENTATION_CEILINGS, ImageCdnPolicyRegistry, imageCdnPresetReference, type ImageCdnHardLimits, type ImageCdnPresetPolicy, } from "../../src/adapters/browser-transfer/image-cdn/image-cdn-policy.ts"; import { computeImageCapabilityBindingDigestHex, createImageCdnRuntime, DEFAULT_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS, MAX_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS, type ImageCapabilityVerificationScheduler, } from "../../src/adapters/browser-transfer/image-cdn/image-cdn-runtime.ts"; import { createP256ImageCapabilityVerifier } from "../../src/adapters/browser-transfer/image-cdn/p256-image-capability-verifier.ts"; const hardLimits: ImageCdnHardLimits = Object.freeze({ maxIntrinsicWidth: 4_096, maxIntrinsicHeight: 4_096, maxSourcePixels: 16_777_216, maxCssDimension: 2_048, maxDpr: 2, maxQuality: 90, maxCandidateCount: 8, maxTransformedPixels: 1_048_576, maxDecodedBytes: 4_194_304, maxEncodedBytes: 524_288, maxUrlLength: 2_048, maxCapabilityLifetimeMs: 3_600_000, maxClockSkewMs: 60_000, minCapabilityRemainingMs: 30_000, maxPresetBindingsPerCapability: 8, maxConcurrentCapabilityVerifications: 8, allowedSourceMediaTypes: [ "image/avif", "image/jpeg", "image/png", "image/webp", ] as const, formatQualityCeilings: { avif: 80, jpeg: 85, png: 90, webp: 85, }, }); function acceptsTestImageKey(keyId: string): boolean { return keyId === "image-signing-2026-01"; } function createPreset( reference: ImagePresetReference, overrides: Partial = {}, ): ImageCdnPresetPolicy { return { reference, bindingId: "card-landscape-v1", width: 640, height: 360, fit: "cover", dprs: [2, 1], responsiveWidths: [640, 320], quality: 80, formats: ["avif", "webp", "jpeg"], sizes: "(max-width: 640px) 100vw, 640px", loading: "eager", decoding: "async", fetchPriority: "high", referrerPolicy: "strict-origin-when-cross-origin", probeMode: "NONE", allowUpscale: false, maxTransformedPixels: 1_048_576, maxDecodedBytes: 4_194_304, maxEncodedBytes: 524_288, ...overrides, }; } function createPolicies( presets: readonly ImageCdnPresetPolicy[], overrides: Readonly<{ hardLimits?: ImageCdnHardLimits; acceptedKeyIds?: readonly string[]; }> = {}, ): ImageCdnPolicyRegistry { return new ImageCdnPolicyRegistry({ applicationOrigin: "https://app.example.test", origins: [ { originKey: "product-images", origin: "https://images.example.test", assetPathPrefix: "/v1/assets/", minimumPublicMaxAgeSeconds: 31_536_000, }, ], presets, hardLimits: overrides.hardLimits ?? hardLimits, capability: { issuer: "image-bff", acceptedKeyIds: overrides.acceptedKeyIds ?? [ "image-signing-2026-01", ], }, }); } function publicAsset( overrides: Partial = {}, ): PublicImmutableImageAsset { return { kind: "ALLOWLISTED_PUBLIC", originKey: "product-images", assetId: "asset_Q3x8pL", revision: "rev_a8N2kP4z", mediaType: "image/jpeg", contentKind: "RASTER_STATIC", intrinsicWidth: 2_048, intrinsicHeight: 1_152, ...overrides, }; } async function privateAsset( overrides: Partial = {}, ): Promise { const base: BackendIssuedImageAsset = { kind: "BACKEND_ISSUED_PRIVATE", issuer: "image-bff", originKey: "product-images", assetId: "asset_Q3x8pL", revision: "rev_a8N2kP4z", mediaType: "image/jpeg", contentKind: "RASTER_STATIC", intrinsicWidth: 2_048, intrinsicHeight: 1_152, capabilityId: "cap_Z8m2Q7pR", issuedAtEpochMs: 1_000_000, expiresAtEpochMs: 1_300_000, allowedPresetBindingIds: ["card-landscape-v1"], signature: { algorithm: "ECDSA_P256_SHA256", keyId: "image-signing-2026-01", capabilityBindingDigestHex: "0".repeat(64), valueBase64Url: "A".repeat(86), }, ...overrides, }; const descriptor = { ...base, signature: { ...base.signature, ...(overrides.signature ?? {}), }, }; const digest = await computeImageCapabilityBindingDigestHex( globalThis.crypto.subtle, descriptor, ); return { ...descriptor, signature: { ...descriptor.signature, capabilityBindingDigestHex: digest, }, }; } describe("production image CDN runtime", () => { it("builds sorted, duplicate-free responsive candidates from a named preset", async () => { const preset = imageCdnPresetReference( "card-landscape", "render-public-product-image", ); const runtime = createImageCdnRuntime({ policies: createPolicies([createPreset(preset)]), now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: vi.fn().mockResolvedValue(true), }, }); const accepted = runtime.assets.acceptPublicImmutable( publicAsset(), ); expect(accepted.ok).toBe(true); if (!accepted.ok) return; const resolved = await runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, }); expect(resolved.ok).toBe(true); if (!resolved.ok) return; const widthDescriptors = resolved.value.srcSet .split(", ") .map((candidate) => Number(candidate.match(/ (\d+)w$/u)?.[1]), ); expect(widthDescriptors).toEqual([320, 640, 1_280]); expect(new Set(widthDescriptors).size).toBe(3); expect(resolved.value.sources.map((source) => source.type)).toEqual( ["image/avif", "image/webp"], ); expect(resolved.value.fallbackMediaType).toBe("image/jpeg"); expect(resolved.value).toMatchObject({ width: 640, height: 360, loading: "eager", decoding: "async", fetchPriority: "high", crossOrigin: "anonymous", delivery: { class: "PUBLIC_IMMUTABLE", browserCache: "PUBLIC_IMMUTABLE", sharedCache: "PUBLIC_IMMUTABLE", purge: "REVISION_ROLLOVER", expiresAtEpochMs: null, }, decodeBudget: { maximumCandidatePixels: 921_600, maximumDecodedBytes: 3_686_400, }, }); const primary = new URL(resolved.value.src); expect(primary.origin).toBe("https://images.example.test"); expect(primary.pathname).toBe( "/v1/assets/asset_Q3x8pL/rev_a8N2kP4z", ); expect([...primary.searchParams.keys()]).toEqual([ "dpr", "fit", "format", "height", "preset", "quality", "width", ]); expect(Object.fromEntries(primary.searchParams)).toEqual({ dpr: "1", fit: "cover", format: "jpeg", height: "360", preset: "card-landscape-v1", quality: "80", width: "640", }); }); it("rejects raw URL/query/transform input and forged preset or asset references", async () => { const preset = imageCdnPresetReference( "card-landscape", "render-public-product-image", ); const runtime = createImageCdnRuntime({ policies: createPolicies([createPreset(preset)]), now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: vi.fn().mockResolvedValue(true), }, }); expect( runtime.assets.acceptPublicImmutable({ ...publicAsset(), sourceUrl: `${"java"}script:alert(1)`, } as PublicImmutableImageAsset), ).toMatchObject({ ok: false, error: { code: "INVALID_INPUT" }, }); expect( runtime.assets.acceptPublicImmutable( publicAsset({ assetId: "../../admin?width=9999", }), ), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); expect( runtime.assets.acceptPublicImmutable( publicAsset({ mediaType: "image/svg+xml", } as unknown as Partial), ), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); const accepted = runtime.assets.acceptPublicImmutable( publicAsset(), ); expect(accepted.ok).toBe(true); if (!accepted.ok) return; await expect( runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, width: 9_999, query: "format=svg", src: "data:text/html,active", } as unknown as Parameters[0]), ).resolves.toMatchObject({ ok: false, error: { code: "INVALID_INPUT" }, }); await expect( runtime.presentation.resolve({ asset: accepted.value, preset: imageCdnPresetReference( "card-landscape", "render-public-product-image", ), signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); await expect( runtime.presentation.resolve({ asset: {} as typeof accepted.value, preset, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); }); it("deep-snapshots origin and preset policy against TOCTOU mutation", async () => { const presetReference = imageCdnPresetReference( "card-landscape", "render-public-product-image", ); const origin = { originKey: "product-images", origin: "https://images.example.test", assetPathPrefix: "/v1/assets/", minimumPublicMaxAgeSeconds: 31_536_000, }; const preset = createPreset(presetReference); const policies = new ImageCdnPolicyRegistry({ applicationOrigin: "https://app.example.test", origins: [origin], presets: [preset], hardLimits, capability: { issuer: "image-bff", acceptedKeyIds: ["image-signing-2026-01"], }, }); origin.origin = "https://attacker.invalid"; origin.assetPathPrefix = "/stolen/"; (preset.dprs as number[])[0] = 4; (preset.formats as string[])[0] = "svg"; (preset as { quality: number }).quality = 100; const runtime = createImageCdnRuntime({ policies }); const accepted = runtime.assets.acceptPublicImmutable( publicAsset(), ); expect(accepted.ok).toBe(true); if (!accepted.ok) return; const resolved = await runtime.presentation.resolve({ asset: accepted.value, preset: presetReference, signal: new AbortController().signal, }); expect(resolved.ok).toBe(true); if (!resolved.ok) return; const url = new URL(resolved.value.src); expect(url.origin).toBe("https://images.example.test"); expect(url.pathname.startsWith("/v1/assets/")).toBe(true); expect(url.searchParams.get("quality")).toBe("80"); expect(resolved.value.sources[0]?.type).toBe("image/avif"); }); it("rejects unsafe origins and preset budgets at composition time", () => { const preset = imageCdnPresetReference( "unsafe", "reject-policy", ); expect( () => new ImageCdnPolicyRegistry({ applicationOrigin: "https://app.example.test", origins: [ { originKey: "bad", origin: "http://user:password@example.test/?q=x#x", assetPathPrefix: "/../assets/", minimumPublicMaxAgeSeconds: 1, }, ], presets: [createPreset(preset)], hardLimits, capability: { issuer: "image-bff", acceptedKeyIds: ["image-signing-2026-01"], }, }), ).toThrow(/origin policy/u); expect( () => createPolicies([ createPreset(preset, { maxTransformedPixels: 100, maxDecodedBytes: 400, }), ]), ).toThrow(/pixel budget/u); const validRegistryOptions = { origins: [ { originKey: "product-images", origin: "https://images.example.test", assetPathPrefix: "/v1/assets/", minimumPublicMaxAgeSeconds: 31_536_000, }, ], presets: [createPreset(preset)], hardLimits, capability: { issuer: "image-bff", acceptedKeyIds: ["image-signing-2026-01"], }, }; expect( () => new ImageCdnPolicyRegistry({ ...validRegistryOptions, applicationOrigin: "https://images.example.test", }), ).toThrow(/cross-origin/u); for (const applicationOrigin of [ "http://app.example.test", "https://app.example.test/", ]) { expect( () => new ImageCdnPolicyRegistry({ ...validRegistryOptions, applicationOrigin, }), ).toThrow(/application origin/u); } }); it("enforces immutable implementation ceilings on every resource-bearing hard limit", () => { const preset = imageCdnPresetReference( "absolute-ceilings", "bound-image-composition", ); const ceiling = IMAGE_CDN_IMPLEMENTATION_CEILINGS; const overCeiling: readonly Partial[] = [ { maxIntrinsicWidth: ceiling.maxIntrinsicWidth + 1 }, { maxIntrinsicHeight: ceiling.maxIntrinsicHeight + 1 }, { maxSourcePixels: ceiling.maxSourcePixels + 1 }, { maxCssDimension: ceiling.maxCssDimension + 1 }, { maxDpr: ceiling.maxDpr + 1 }, { maxQuality: ceiling.maxQuality + 1 }, { maxCandidateCount: ceiling.maxCandidateCount + 1 }, { maxTransformedPixels: ceiling.maxTransformedPixels + 1, }, { maxDecodedBytes: ceiling.maxDecodedBytes + 1 }, { maxEncodedBytes: ceiling.maxEncodedBytes + 1 }, { maxUrlLength: ceiling.maxUrlLength + 1 }, { maxCapabilityLifetimeMs: ceiling.maxCapabilityLifetimeMs + 1, }, { maxClockSkewMs: ceiling.maxClockSkewMs + 1 }, { minCapabilityRemainingMs: ceiling.maxMinimumCapabilityRemainingMs + 1, }, { maxPresetBindingsPerCapability: ceiling.maxPresetBindingsPerCapability + 1, }, { maxConcurrentCapabilityVerifications: ceiling.maxConcurrentCapabilityVerifications + 1, }, ]; for (const override of overCeiling) { expect(() => createPolicies([createPreset(preset)], { hardLimits: { ...hardLimits, ...override }, }), ).toThrow(/hard limits/u); } const boundaryLimits: ImageCdnHardLimits = { ...hardLimits, maxIntrinsicWidth: ceiling.maxIntrinsicWidth, maxIntrinsicHeight: ceiling.maxIntrinsicHeight, maxSourcePixels: ceiling.maxSourcePixels, maxCssDimension: ceiling.maxCssDimension, maxDpr: ceiling.maxDpr, maxQuality: ceiling.maxQuality, maxCandidateCount: ceiling.maxCandidateCount, maxTransformedPixels: ceiling.maxTransformedPixels, maxDecodedBytes: ceiling.maxDecodedBytes, maxEncodedBytes: ceiling.maxEncodedBytes, maxUrlLength: ceiling.maxUrlLength, maxCapabilityLifetimeMs: ceiling.maxCapabilityLifetimeMs, maxClockSkewMs: ceiling.maxClockSkewMs, minCapabilityRemainingMs: ceiling.maxMinimumCapabilityRemainingMs, maxPresetBindingsPerCapability: ceiling.maxPresetBindingsPerCapability, maxConcurrentCapabilityVerifications: ceiling.maxConcurrentCapabilityVerifications, }; expect(() => createPolicies([createPreset(preset)], { hardLimits: boundaryLimits, }), ).not.toThrow(); }); it("snapshots a bounded unique capability-key overlap set", () => { const preset = imageCdnPresetReference( "key-policy", "rotate-image-signing-key", ); for (const acceptedKeyIds of [ [], ["image-key-current", "image-key-current"], Array.from( { length: IMAGE_CDN_IMPLEMENTATION_CEILINGS.maxAcceptedKeyIds + 1, }, (_, index) => `image-key-${index}`, ), ["image-key-current", "invalid/key"], ]) { expect(() => createPolicies([createPreset(preset)], { acceptedKeyIds, }), ).toThrow(/capability policy/u); } const mutableKeyIds = [ "image-signing-2026-02", "image-signing-2026-01", ]; const policies = createPolicies([createPreset(preset)], { acceptedKeyIds: mutableKeyIds, }); mutableKeyIds[0] = "image-signing-attacker"; expect(policies.capabilityPolicy().acceptedKeyIds).toEqual([ "image-signing-2026-02", "image-signing-2026-01", ]); expect( Object.isFrozen( policies.capabilityPolicy().acceptedKeyIds, ), ).toBe(true); }); it("accepts old and new overlap keys only when policy and verifier registries both cover them", async () => { const preset = imageCdnPresetReference( "key-overlap", "verify-image-key-rotation", ); const acceptedKeyIds = [ "image-signing-2026-02", "image-signing-2026-01", ] as const; const policies = createPolicies([createPreset(preset)], { acceptedKeyIds, }); const verifierKeys = new Set(acceptedKeyIds); const verify = vi.fn( async (request: { keyId: string }) => verifierKeys.has(request.keyId), ); const runtime = createImageCdnRuntime({ policies, now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: (keyId) => verifierKeys.has(keyId), verify, }, }); const previous = await privateAsset(); const current = await privateAsset({ signature: { algorithm: "ECDSA_P256_SHA256", keyId: "image-signing-2026-02", capabilityBindingDigestHex: "0".repeat(64), valueBase64Url: "A".repeat(86), }, }); await expect( runtime.assets.acceptBackendIssued(previous), ).resolves.toMatchObject({ ok: true }); await expect( runtime.assets.acceptBackendIssued(current), ).resolves.toMatchObject({ ok: true }); expect(verify.mock.calls.map(([request]) => request.keyId)).toEqual( ["image-signing-2026-01", "image-signing-2026-02"], ); const unknown = await privateAsset({ signature: { algorithm: "ECDSA_P256_SHA256", keyId: "image-signing-2027-01", capabilityBindingDigestHex: "0".repeat(64), valueBase64Url: "A".repeat(86), }, }); await expect( runtime.assets.acceptBackendIssued(unknown), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); expect(verify).toHaveBeenCalledTimes(2); expect(() => createImageCdnRuntime({ policies, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: (keyId) => keyId === "image-signing-2026-02", verify: vi.fn().mockResolvedValue(true), }, }), ).toThrow(/registry does not cover/u); expect(() => createImageCdnRuntime({ policies, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey() { throw new TypeError("registry unavailable"); }, verify: vi.fn().mockResolvedValue(true), }, }), ).toThrow(/registry does not cover/u); }); it("binds a private descriptor to its signed snapshot and exact preset", async () => { const preset = imageCdnPresetReference( "card-landscape", "render-private-product-image", ); const policies = createPolicies([ createPreset(preset, { probeMode: "PRIMARY_REQUIRED", }), ]); let releaseVerification: ((value: boolean) => void) | undefined; const verifierMethod = vi.fn( () => new Promise((resolve) => { releaseVerification = resolve; }), ); const verifier: ImageCapabilityVerifier = { acceptsKey: acceptsTestImageKey, verify: verifierMethod, }; let now = 1_000_000; const runtime = createImageCdnRuntime({ policies, now: () => now, subtle: globalThis.crypto.subtle, capabilityVerifier: verifier, probe: { async probe(request) { return { ok: true, value: { absoluteUrl: request.absoluteUrl, mediaType: request.expectedMediaType, encodedBytes: 1_024, decodedWidth: request.expectedWidth, decodedHeight: request.expectedHeight, }, }; }, }, }); ( verifier as { verify: ImageCapabilityVerifier["verify"]; } ).verify = vi.fn().mockResolvedValue(false); const mutable = (await privateAsset()) as { -readonly [Key in keyof BackendIssuedImageAsset]: BackendIssuedImageAsset[Key]; }; const pending = runtime.assets.acceptBackendIssued(mutable); await vi.waitFor(() => { expect(verifierMethod).toHaveBeenCalledOnce(); }); mutable.assetId = "asset_ATTACKER"; mutable.revision = "rev_ATTACKER"; mutable.expiresAtEpochMs = 9_999_999; releaseVerification?.(true); const accepted = await pending; expect(accepted.ok).toBe(true); if (!accepted.ok) return; const resolved = await runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, }); expect(resolved.ok).toBe(true); if (!resolved.ok) return; const url = new URL(resolved.value.src); expect(url.pathname).toContain( "/asset_Q3x8pL/rev_a8N2kP4z", ); expect(url.pathname).not.toContain("ATTACKER"); expect([...url.searchParams.keys()]).toEqual([ "binding", "capability", "dpr", "expires", "fit", "format", "height", "key", "preset", "quality", "signature", "width", ]); expect(resolved.value).toMatchObject({ loading: "eager", referrerPolicy: "no-referrer", crossOrigin: "anonymous", delivery: { class: "PRIVATE_SIGNED", browserCache: "NO_STORE", sharedCache: "FORBIDDEN", purge: "CAPABILITY_REVOCATION_OR_EXPIRY", expiresAtEpochMs: 1_300_000, }, }); now = 1_275_001; await expect( runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "EXPIRED_RESOURCE" }, }); }); it("rejects invalid binding/signature and private lazy or low-priority presets", async () => { const eager = imageCdnPresetReference( "private-eager", "render-private", ); const lazy = imageCdnPresetReference( "private-lazy", "render-private", ); const policies = createPolicies([ createPreset(eager, { bindingId: "private-eager-v1", }), createPreset(lazy, { bindingId: "private-lazy-v1", loading: "lazy", fetchPriority: "low", }), ]); const runtime = createImageCdnRuntime({ policies, now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: vi.fn().mockResolvedValue(true), }, }); const issued = await privateAsset({ allowedPresetBindingIds: [ "private-eager-v1", "private-lazy-v1", ], }); const accepted = await runtime.assets.acceptBackendIssued(issued); expect(accepted.ok).toBe(true); if (!accepted.ok) return; await expect( runtime.presentation.resolve({ asset: accepted.value, preset: eager, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); await expect( runtime.presentation.resolve({ asset: accepted.value, preset: lazy, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); await expect( runtime.assets.acceptBackendIssued({ ...issued, signature: { ...issued.signature, capabilityBindingDigestHex: "f".repeat(64), }, }), ).resolves.toMatchObject({ ok: false, error: { code: "INTEGRITY_FAILED" }, }); const rejectingRuntime = createImageCdnRuntime({ policies, now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: vi.fn().mockResolvedValue(false), }, }); await expect( rejectingRuntime.assets.acceptBackendIssued(issued), ).resolves.toMatchObject({ ok: false, error: { code: "INTEGRITY_FAILED" }, }); }); it("bounds digest and capability verification with a runtime-owned deadline and caller abort", async () => { const preset = imageCdnPresetReference( "deadline", "verify-private-capability", ); const policies = createPolicies([createPreset(preset)]); const issued = await privateAsset(); const observations: Record[] = []; const verifierDeadline = manualCapabilityVerificationScheduler(); const stalledVerifier = vi.fn( () => new Promise(() => undefined), ); const verifierRuntime = createImageCdnRuntime({ policies, now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: stalledVerifier, }, capabilityVerificationScheduler: verifierDeadline.scheduler, observer: { record(observation) { observations.push(observation); }, }, }); const verifierPending = verifierRuntime.assets.acceptBackendIssued(issued); await vi.waitFor(() => { expect(stalledVerifier).toHaveBeenCalledOnce(); }); expect(verifierDeadline.delays).toEqual([ DEFAULT_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS, ]); verifierDeadline.fire(); await expect(verifierPending).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE", retryable: true, recovery: "RETRY", }, }); expect(verifierDeadline.clearTimeout).toHaveBeenCalledOnce(); expect(observations).toEqual([ expect.objectContaining({ operation: "IMAGE_RESOLVE", outcome: "FAILED", failureCode: "UNAVAILABLE", countBucket: "ZERO", }), ]); const digestDeadline = manualCapabilityVerificationScheduler(); const stalledDigest = vi.fn( () => new Promise(() => undefined), ); const digestVerifier = vi.fn().mockResolvedValue(true); const digestRuntime = createImageCdnRuntime({ policies, now: () => 1_000_000, subtle: { digest: stalledDigest as SubtleCrypto["digest"], }, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: digestVerifier, }, capabilityVerificationTimeoutMs: MAX_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS, capabilityVerificationScheduler: digestDeadline.scheduler, }); const digestPending = digestRuntime.assets.acceptBackendIssued(issued); await vi.waitFor(() => { expect(stalledDigest).toHaveBeenCalledOnce(); }); expect(digestDeadline.delays).toEqual([ MAX_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS, ]); digestDeadline.fire(); await expect(digestPending).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE" }, }); expect(digestVerifier).not.toHaveBeenCalled(); const abortDeadline = manualCapabilityVerificationScheduler(); const abortVerifier = vi.fn( () => new Promise(() => undefined), ); const abortRuntime = createImageCdnRuntime({ policies, now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: abortVerifier, }, capabilityVerificationScheduler: abortDeadline.scheduler, }); const controller = new AbortController(); const abortPending = abortRuntime.assets.acceptBackendIssued( issued, { signal: controller.signal }, ); await vi.waitFor(() => { expect(abortVerifier).toHaveBeenCalledOnce(); }); controller.abort(); await expect(abortPending).resolves.toMatchObject({ ok: false, error: { code: "ABORTED" }, }); expect(abortDeadline.clearTimeout).toHaveBeenCalledOnce(); }); /** * TR-RR-07. The concurrency cap exists to bound *physical* verification work. * Releasing the slot when the wrapper's abort resolved let an abandoned * verifier keep running while a new one was admitted, so repeated aborts * produced more concurrent work than the configured cap allows. */ it("holds the verification slot until the raw verifier settles", async () => { const preset = imageCdnPresetReference( "verification-concurrency", "bound-image-verification-concurrency", ); const policies = createPolicies([createPreset(preset)], { hardLimits: { ...hardLimits, maxConcurrentCapabilityVerifications: 1, }, }); let verificationAttempt = 0; let releaseFirst: ((value: boolean) => void) | undefined; const verify = vi.fn(() => { verificationAttempt += 1; return verificationAttempt === 1 ? new Promise((resolve) => { releaseFirst = resolve; }) : Promise.resolve(true); }); const runtime = createImageCdnRuntime({ policies, now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify, }, }); const issued = await privateAsset(); const controller = new AbortController(); const first = runtime.assets.acceptBackendIssued(issued, { signal: controller.signal, }); await vi.waitFor(() => { expect(verify).toHaveBeenCalledOnce(); }); await expect( runtime.assets.acceptBackendIssued(issued), ).resolves.toMatchObject({ ok: false, error: { code: "LIMIT_EXCEEDED" }, }); expect(verify).toHaveBeenCalledOnce(); controller.abort(); await expect(first).resolves.toMatchObject({ ok: false, error: { code: "ABORTED" }, }); // The caller's wait ended, but the raw verifier has not. Admitting a second // one here would put two physical verifications under a cap of one. await expect( runtime.assets.acceptBackendIssued(issued), ).resolves.toMatchObject({ ok: false, error: { code: "LIMIT_EXCEEDED" }, }); expect(verify).toHaveBeenCalledOnce(); // Once the raw verifier settles the slot is free again. releaseFirst?.(true); await vi.waitFor(async () => { await expect( runtime.assets.acceptBackendIssued(issued), ).resolves.toMatchObject({ ok: true }); }); expect(verify).toHaveBeenCalledTimes(2); }); it("fails fast on invalid capability verification deadline composition", () => { const preset = imageCdnPresetReference( "deadline-config", "validate-private-capability-deadline", ); const policies = createPolicies([createPreset(preset)]); expect( DEFAULT_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS, ).toBe(5_000); expect(MAX_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS).toBe( 60_000, ); for (const capabilityVerificationTimeoutMs of [ 0, 1.5, MAX_IMAGE_CAPABILITY_VERIFICATION_TIMEOUT_MS + 1, ]) { expect(() => createImageCdnRuntime({ policies, capabilityVerificationTimeoutMs, }), ).toThrow(/verification timeout/u); } expect(() => createImageCdnRuntime({ policies, capabilityVerificationScheduler: { setTimeout: null, clearTimeout: vi.fn(), } as unknown as ImageCapabilityVerificationScheduler, }), ).toThrow(/verification scheduler/u); }); it("closes terminally and idempotently, revoking old references and rejecting every later operation", async () => { const preset = imageCdnPresetReference( "lifecycle", "close-image-runtime", ); const runtime = createImageCdnRuntime({ policies: createPolicies([createPreset(preset)]), now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: vi.fn().mockResolvedValue(true), }, }); const accepted = runtime.assets.acceptPublicImmutable(publicAsset()); expect(accepted.ok).toBe(true); if (!accepted.ok) return; await expect( runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: true }); const acceptedPrivate = await runtime.assets.acceptBackendIssued( await privateAsset(), ); expect(acceptedPrivate.ok).toBe(true); if (!acceptedPrivate.ok) return; runtime.close(); expect(() => runtime.close()).not.toThrow(); await expect( runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE", retryable: false, recovery: "NONE", }, }); await expect( runtime.presentation.resolve({ asset: acceptedPrivate.value, preset, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE" }, }); expect( runtime.assets.acceptPublicImmutable(publicAsset()), ).toMatchObject({ ok: false, error: { code: "UNAVAILABLE" }, }); await expect( runtime.assets.acceptBackendIssued(await privateAsset()), ).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE" }, }); }); it("close aborts stalled private verification and image probing", async () => { const verifierPreset = imageCdnPresetReference( "close-verifier", "abort-image-verification", ); const verifierDeadline = manualCapabilityVerificationScheduler(); const stalledVerifier = vi.fn( () => new Promise(() => undefined), ); const verifierRuntime = createImageCdnRuntime({ policies: createPolicies([ createPreset(verifierPreset), ]), now: () => 1_000_000, subtle: globalThis.crypto.subtle, capabilityVerifier: { acceptsKey: acceptsTestImageKey, verify: stalledVerifier, }, capabilityVerificationScheduler: verifierDeadline.scheduler, }); const verificationPending = verifierRuntime.assets.acceptBackendIssued( await privateAsset(), ); await vi.waitFor(() => { expect(stalledVerifier).toHaveBeenCalledOnce(); }); verifierRuntime.close(); await expect(verificationPending).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE", retryable: false }, }); expect(verifierDeadline.clearTimeout).toHaveBeenCalledOnce(); const probePreset = imageCdnPresetReference( "close-probe", "abort-image-probe", ); const stalledProbe = vi.fn( (_request: ImageProbeRequest) => new Promise(() => undefined), ); const probeRuntime = createImageCdnRuntime({ policies: createPolicies([ createPreset(probePreset, { probeMode: "PRIMARY_REQUIRED", }), ]), probe: { probe: stalledProbe }, }); const accepted = probeRuntime.assets.acceptPublicImmutable(publicAsset()); expect(accepted.ok).toBe(true); if (!accepted.ok) return; const caller = new AbortController(); const probePending = probeRuntime.presentation.resolve({ asset: accepted.value, preset: probePreset, signal: caller.signal, }); await vi.waitFor(() => { expect(stalledProbe).toHaveBeenCalledOnce(); }); const runtimeSignal = stalledProbe.mock.calls[0]?.[0].signal; expect(runtimeSignal).not.toBe(caller.signal); probeRuntime.close(); await expect(probePending).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE", retryable: false }, }); expect(runtimeSignal?.aborted).toBe(true); }); it("requires and validates the bounded probe receipt when the preset says so", async () => { const preset = imageCdnPresetReference( "probed", "render-verified-image", ); const policy = createPreset(preset, { bindingId: "probed-v1", probeMode: "PRIMARY_REQUIRED", }); const withoutProbe = createImageCdnRuntime({ policies: createPolicies([policy]), }); const noProbeAsset = withoutProbe.assets.acceptPublicImmutable(publicAsset()); expect(noProbeAsset.ok).toBe(true); if (!noProbeAsset.ok) return; await expect( withoutProbe.presentation.resolve({ asset: noProbeAsset.value, preset, signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "UNSUPPORTED" }, }); const probe = vi.fn(async (request: ImageProbeRequest) => ({ ok: true as const, value: { absoluteUrl: request.absoluteUrl, mediaType: request.expectedMediaType, encodedBytes: 1_024, decodedWidth: request.expectedWidth, decodedHeight: request.expectedHeight, }, })); const runtime = createImageCdnRuntime({ policies: createPolicies([policy]), probe: { probe }, }); const accepted = runtime.assets.acceptPublicImmutable(publicAsset()); expect(accepted.ok).toBe(true); if (!accepted.ok) return; const resolved = await runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, }); expect(resolved.ok).toBe(true); expect(probe).toHaveBeenCalledWith( expect.objectContaining({ expectedMediaType: "image/jpeg", expectedWidth: 640, expectedHeight: 360, maxEncodedBytes: 524_288, maxDecodedBytes: 4_194_304, delivery: "PUBLIC_IMMUTABLE", }), ); }); it("records only safe terminal buckets for accept, probe and resolve", async () => { const preset = imageCdnPresetReference( "observed", "render-observed-image", ); const observations: Record[] = []; const observer = { record(observation: Record) { observations.push(observation); }, }; const runtime = createImageCdnRuntime({ policies: createPolicies([ createPreset(preset, { bindingId: "observed-v1", probeMode: "PRIMARY_REQUIRED", }), ]), observer, probe: { async probe(request) { return { ok: true, value: { absoluteUrl: request.absoluteUrl, mediaType: request.expectedMediaType, encodedBytes: 2_048, decodedWidth: request.expectedWidth, decodedHeight: request.expectedHeight, }, }; }, }, }); observer.record = () => { throw new TypeError("mutated observer must not be observed"); }; const accepted = runtime.assets.acceptPublicImmutable(publicAsset()); expect(accepted.ok).toBe(true); if (!accepted.ok) return; const resolved = await runtime.presentation.resolve({ asset: accepted.value, preset, signal: new AbortController().signal, }); expect(resolved.ok).toBe(true); expect(observations).toHaveLength(3); for (const observation of observations) { expect(observation).toMatchObject({ operation: "IMAGE_RESOLVE", outcome: "SUCCEEDED", }); expect(Object.keys(observation)).not.toEqual( expect.arrayContaining([ "assetId", "preset", "capability", "signature", "url", ]), ); expect(JSON.stringify(observation)).not.toContain( "images.example.test", ); } expect(observations.map((value) => value.countBucket)).toEqual([ "ONE", "ONE", "TWO_TO_TEN", ]); expect(observations.map((value) => value.byteBucket)).toEqual([ undefined, "LT1MIB", "LT1MIB", ]); }); }); describe("browser image probe", () => { const imageUrl = "https://images.example.test/v1/assets/a/rev?format=png"; const request = ( overrides: Partial = {}, ): ImageProbeRequest => ({ absoluteUrl: imageUrl, expectedMediaType: "image/png", expectedWidth: 640, expectedHeight: 360, maxEncodedBytes: 1_024, maxDecodedPixels: 230_400, maxDecodedBytes: 921_600, delivery: "PUBLIC_IMMUTABLE", minimumPublicMaxAgeSeconds: 31_536_000, referrerPolicy: "no-referrer", signal: new AbortController().signal, ...overrides, }); it("parses all supported static headers before decode and closes each bitmap", async () => { const samples = [ { mediaType: "image/png" as const, bytes: pngBytes(640, 360), }, { mediaType: "image/jpeg" as const, bytes: jpegBytes(640, 360), }, { mediaType: "image/webp" as const, bytes: webpBytes(640, 360), }, { mediaType: "image/avif" as const, bytes: avifBytes(640, 360), }, ]; const close = vi.fn(); for (const sample of samples) { const exactUrl = imageUrl.replace( "format=png", `format=${sample.mediaType.slice("image/".length)}`, ); const fetcher = vi.fn(async () => responseAt(exactUrl, sample.bytes, { status: 200, headers: publicImageHeaders( sample.mediaType, sample.bytes.byteLength, ), }), ); const probe = createBrowserImageProbe({ fetcher: fetcher as typeof fetch, createBitmap: vi.fn(async () => ({ width: 640, height: 360, close, })), }); await expect( probe.probe( request({ absoluteUrl: exactUrl, expectedMediaType: sample.mediaType, }), ), ).resolves.toMatchObject({ ok: true, value: { absoluteUrl: exactUrl, mediaType: sample.mediaType, encodedBytes: sample.bytes.byteLength, decodedWidth: 640, decodedHeight: 360, }, }); expect(fetcher).toHaveBeenCalledWith( exactUrl, expect.objectContaining({ credentials: "omit", redirect: "error", mode: "cors", cache: "no-store", referrerPolicy: "no-referrer", }), ); } expect(close).toHaveBeenCalledTimes(samples.length); }); it("fails closed on duplicate/conflicting cache directives and oversized bodies", async () => { const png = pngBytes(640, 360); const createBitmap = vi.fn(async () => ({ width: 640, height: 360, close: vi.fn(), })); for (const cacheControl of [ // BT-IMG-02. Unmatched quotes must not be unwrapped into a bare number. 'public, max-age="31536000, immutable', 'public, max-age=31536000", immutable', 'public, max-age="31536000\\", immutable', "public, public, max-age=31536000, immutable", "public, max-age=31536000, s-maxage=60, immutable", "public, max-age=31536000, immutable, must-revalidate", "public=1, max-age=31536000, immutable", "public, max-age=31536000, immutable=true", ]) { const probe = createBrowserImageProbe({ fetcher: (async () => responseAt(imageUrl, png, { status: 200, headers: { "cache-control": cacheControl, "content-type": "image/png", }, })) as typeof fetch, createBitmap, }); await expect(probe.probe(request())).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); } const probe = createBrowserImageProbe({ fetcher: (async () => responseAt(imageUrl, new Uint8Array(2_048), { status: 200, headers: { "cache-control": "public, max-age=31536000, immutable", "content-type": "image/png", }, })) as typeof fetch, createBitmap, }); await expect(probe.probe(request())).resolves.toMatchObject({ ok: false, error: { code: "LIMIT_EXCEEDED" }, }); expect(createBitmap).not.toHaveBeenCalled(); }); it("rejects non-identity content encoding and mismatched declared lengths", async () => { const png = pngBytes(640, 360); const createBitmap = vi.fn(); const cases = [ { headers: { "content-encoding": "gzip", "content-length": String(png.byteLength), }, code: "POLICY_REJECTED", }, { headers: { "content-length": String(png.byteLength + 1), }, code: "INTEGRITY_FAILED", }, ]; for (const invalid of cases) { const headers = publicImageHeaders("image/png"); for (const [name, value] of Object.entries(invalid.headers)) { headers.set(name, value); } const probe = createBrowserImageProbe({ fetcher: (async () => responseAt(imageUrl, png, { status: 200, headers, })) as typeof fetch, createBitmap, }); await expect(probe.probe(request())).resolves.toMatchObject({ ok: false, error: { code: invalid.code }, }); } expect(createBitmap).not.toHaveBeenCalled(); }); it("rejects malicious dimensions and animated PNG/WebP before native decode", async () => { const createBitmap = vi.fn(async () => ({ width: 640, height: 360, close: vi.fn(), })); const cases = [ { bytes: pngBytes(20_000, 20_000), mediaType: "image/png" as const, code: "LIMIT_EXCEEDED", }, { bytes: pngBytes(320, 180), mediaType: "image/png" as const, code: "INTEGRITY_FAILED", }, { bytes: jpegBytes(320, 180), mediaType: "image/jpeg" as const, code: "INTEGRITY_FAILED", }, { bytes: webpBytes(10_000, 10_000), mediaType: "image/webp" as const, code: "LIMIT_EXCEEDED", }, { bytes: avifBytes(20_000, 20_000), mediaType: "image/avif" as const, code: "LIMIT_EXCEEDED", }, { bytes: pngBytes(640, 360, true), mediaType: "image/png" as const, code: "INTEGRITY_FAILED", }, { bytes: webpBytes(640, 360, true), mediaType: "image/webp" as const, code: "INTEGRITY_FAILED", }, { bytes: avifBytes(640, 360, "avis"), mediaType: "image/avif" as const, code: "INTEGRITY_FAILED", }, ]; for (const malicious of cases) { const url = imageUrl.replace( "format=png", `format=${malicious.mediaType.slice("image/".length)}`, ); const probe = createBrowserImageProbe({ fetcher: (async () => responseAt(url, malicious.bytes, { status: 200, headers: publicImageHeaders( malicious.mediaType, malicious.bytes.byteLength, ), })) as typeof fetch, createBitmap, }); await expect( probe.probe( request({ absoluteUrl: url, expectedMediaType: malicious.mediaType, }), ), ).resolves.toMatchObject({ ok: false, error: { code: malicious.code }, }); } expect(createBitmap).not.toHaveBeenCalled(); }); it("enforces private no-store, omitted credentials and the exact final URL", async () => { const png = pngBytes(640, 360); const fetcher = vi.fn(async () => responseAt(imageUrl, png, { status: 200, headers: { // TR-RR-09. A private response carries `no-store` and nothing else // that describes cacheability. "cache-control": "no-store", "content-type": "image/png", }, }), ); const probe = createBrowserImageProbe({ fetcher: fetcher as typeof fetch, createBitmap: async () => ({ width: 640, height: 360, close: vi.fn(), }), }); await expect( probe.probe( request({ delivery: "PRIVATE_SIGNED", minimumPublicMaxAgeSeconds: 0, }), ), ).resolves.toMatchObject({ ok: true }); expect(fetcher).toHaveBeenCalledWith( imageUrl, expect.objectContaining({ cache: "no-store", credentials: "omit", redirect: "error", }), ); for (const response of [ responseAt(imageUrl, png, { status: 200, headers: { "cache-control": "private, no-store=value", "content-type": "image/png", }, }), responseAt(imageUrl, png, { status: 200, headers: { "cache-control": "public, no-store", "content-type": "image/png", }, }), responseAt( "https://images.example.test/v1/assets/other", png, { status: 200, headers: { "cache-control": "private, no-store", "content-type": "image/png", }, }, ), ]) { const rejectingProbe = createBrowserImageProbe({ fetcher: (async () => response) as typeof fetch, createBitmap: async () => ({ width: 640, height: 360, close: vi.fn(), }), }); await expect( rejectingProbe.probe( request({ delivery: "PRIVATE_SIGNED", minimumPublicMaxAgeSeconds: 0, }), ), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); } await expect( probe.probe( request({ expectedMediaType: "image/svg+xml", } as unknown as Partial), ), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); }); /** * TR-RR-09. The recorded BT-IMG-02 contract for a private response is a * fail-closed matrix. Accepting `no-store` next to a directive that describes * cacheability lets a self-contradictory policy read as acceptable. */ it("applies the full private Cache-Control matrix", async () => { const png = pngBytes(640, 360); const probeWith = async (cacheControl: string) => { const probe = createBrowserImageProbe({ fetcher: (async () => responseAt(imageUrl, png, { status: 200, headers: { "cache-control": cacheControl, "content-type": "image/png", }, })) as typeof fetch, createBitmap: async () => ({ width: 640, height: 360, close: vi.fn(), }), }); return await probe.probe( request({ delivery: "PRIVATE_SIGNED", minimumPublicMaxAgeSeconds: 0, }), ); }; // Only `no-store`, plus a syntactically valid unknown extension. expect(await probeWith("no-store")).toMatchObject({ ok: true }); expect(await probeWith('no-store, x-vendor="a,b"')).toMatchObject({ ok: true, }); for (const companion of [ "public", "private", "immutable", "max-age=60", "s-maxage=60", "no-cache", "must-revalidate", "proxy-revalidate", ]) { expect(await probeWith(`no-store, ${companion}`)).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); } for (const withoutNoStore of ["private", "no-cache", "max-age=0"]) { expect(await probeWith(withoutNoStore)).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); } }); it("times out a stalled body, aborts the composed signal and cancels its reader", async () => { const manual = manualImageProbeScheduler(); const cancel = vi.fn(async () => undefined); const releaseLock = vi.fn(); const read = vi.fn( () => new Promise>( () => undefined, ), ); const response = { body: { getReader: () => ({ cancel, read, releaseLock }), }, headers: publicImageHeaders("image/png"), ok: true, redirected: false, status: 200, type: "cors", url: imageUrl, } as unknown as Response; const fetcher = vi.fn( async (_input: RequestInfo | URL, _init?: RequestInit) => response, ); const probe = createBrowserImageProbe({ fetcher: fetcher as typeof fetch, createBitmap: vi.fn(), timeoutMs: 1_000, scheduler: manual.scheduler, }); const probeRequest = request(); const pending = probe.probe(probeRequest); await vi.waitFor(() => { expect(read).toHaveBeenCalledOnce(); }); const composedSignal = fetcher.mock.calls[0]?.[1]?.signal as | AbortSignal | null | undefined; expect(composedSignal).not.toBe(probeRequest.signal); manual.fire(); await expect(pending).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE", retryable: true, recovery: "RETRY", }, }); expect(cancel).toHaveBeenCalledOnce(); expect(releaseLock).toHaveBeenCalledOnce(); expect(composedSignal?.aborted).toBe(true); }); it("times out stalled decode and closes a bitmap that resolves late", async () => { const manual = manualImageProbeScheduler(); const close = vi.fn(); let finishDecode: ((bitmap: { width: number; height: number; close(): void; }) => void) | undefined; const createBitmap = vi.fn( () => new Promise<{ width: number; height: number; close(): void; }>((resolve) => { finishDecode = resolve; }), ); const png = pngBytes(640, 360); const probe = createBrowserImageProbe({ fetcher: (async () => responseAt(imageUrl, png, { status: 200, headers: publicImageHeaders("image/png", png.byteLength), })) as typeof fetch, createBitmap, timeoutMs: 1_000, scheduler: manual.scheduler, }); const pending = probe.probe(request()); await vi.waitFor(() => { expect(createBitmap).toHaveBeenCalledOnce(); }); manual.fire(); await expect(pending).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE" }, }); finishDecode?.({ width: 640, height: 360, close }); await vi.waitFor(() => { expect(close).toHaveBeenCalledOnce(); }); }); /** * X-AUDIT-02. `probe()` promises a `BrowserDataResult`. A scheduler that * cannot install the probe deadline must close the probe inside that contract * rather than rejecting it, and must not leave the caller's listener behind. */ describe("scheduler boundary", () => { const trackedSignal = () => { const controller = new AbortController(); const added: string[] = []; const removed: string[] = []; const add = controller.signal.addEventListener.bind(controller.signal); const remove = controller.signal.removeEventListener.bind( controller.signal, ); Object.defineProperty(controller.signal, "addEventListener", { configurable: true, value: (type: string, ...rest: readonly unknown[]) => { added.push(type); return (add as (...args: readonly unknown[]) => unknown)( type, ...rest, ); }, }); Object.defineProperty(controller.signal, "removeEventListener", { configurable: true, value: (type: string, ...rest: readonly unknown[]) => { removed.push(type); return (remove as (...args: readonly unknown[]) => unknown)( type, ...rest, ); }, }); return { controller, added, removed }; }; it("closes the probe when the scheduler cannot install the deadline", async () => { const fetcher = vi.fn(async () => new Response(null, { status: 200 })); const { controller, added, removed } = trackedSignal(); const probe = createBrowserImageProbe({ fetcher: fetcher as unknown as typeof fetch, createBitmap: vi.fn(), timeoutMs: 1_000, scheduler: { setTimeout: () => { throw new TypeError("image scheduler install exploded"); }, clearTimeout: vi.fn(), }, }); await expect( probe.probe({ ...request(), signal: controller.signal }), ).resolves.toMatchObject({ ok: false, error: { code: "UNAVAILABLE", retryable: true, recovery: "RETRY" }, }); expect(fetcher).not.toHaveBeenCalled(); expect(added.filter((type) => type === "abort")).toHaveLength(1); expect(removed.filter((type) => type === "abort")).toHaveLength(1); }); it("starts no timer and no fetch for an already aborted caller", async () => { const fetcher = vi.fn(async () => new Response(null, { status: 200 })); const setTimeout_ = vi.fn(() => 1); const controller = new AbortController(); controller.abort(); const probe = createBrowserImageProbe({ fetcher: fetcher as unknown as typeof fetch, createBitmap: vi.fn(), timeoutMs: 1_000, scheduler: { setTimeout: setTimeout_, clearTimeout: vi.fn() }, }); await expect( probe.probe({ ...request(), signal: controller.signal }), ).resolves.toMatchObject({ ok: false, error: { code: "ABORTED" } }); expect(fetcher).not.toHaveBeenCalled(); expect(setTimeout_).not.toHaveBeenCalled(); }); it("keeps the classified outcome when clearing the deadline throws", async () => { const png = pngBytes(640, 360); const probe = createBrowserImageProbe({ fetcher: (async () => responseAt(imageUrl, png, { status: 200, headers: publicImageHeaders("image/png", png.byteLength), })) as typeof fetch, createBitmap: vi.fn(async () => ({ width: 640, height: 360, close: vi.fn(), })), timeoutMs: 1_000, scheduler: { setTimeout: (callback: () => void, milliseconds: number) => setTimeout(callback, milliseconds), clearTimeout: () => { throw new TypeError("image scheduler clear exploded"); }, }, }); await expect(probe.probe(request())).resolves.toMatchObject({ ok: true }); }); }); }); describe("P-256 image capability verifier", () => { it("rejects an ECDSA public key on any curve other than P-256", async () => { const generated = await globalThis.crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-384" }, false, ["sign", "verify"], ); if (!("publicKey" in generated)) { throw new TypeError("Expected an ECDSA key pair."); } expect(() => createP256ImageCapabilityVerifier({ subtle: globalThis.crypto.subtle, publicKeys: [ { keyId: "image-signing-wrong-curve", key: generated.publicKey, }, ], }), ).toThrow(/public key binding/u); }); it("verifies the exact canonical payload and rejects tampering", async () => { const generated = await globalThis.crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-256" }, false, ["sign", "verify"], ); if (!("privateKey" in generated)) { throw new TypeError("Expected an ECDSA key pair."); } const payload = new TextEncoder().encode( '["image-cdn-capability-v1","bound"]', ); const payloadBuffer = new Uint8Array(payload.byteLength); payloadBuffer.set(payload); const signature = await globalThis.crypto.subtle.sign( { name: "ECDSA", hash: "SHA-256" }, generated.privateKey, payloadBuffer.buffer, ); const verifier = createP256ImageCapabilityVerifier({ subtle: globalThis.crypto.subtle, publicKeys: [ { keyId: "image-signing-2026-01", key: generated.publicKey, }, ], }); expect(verifier.acceptsKey("image-signing-2026-01")).toBe( true, ); expect(verifier.acceptsKey("image-signing-unknown")).toBe( false, ); const signatureBase64Url = base64Url( new Uint8Array(signature), ); await expect( verifier.verify({ algorithm: "ECDSA_P256_SHA256", keyId: "image-signing-2026-01", canonicalPayload: payload, signatureBase64Url, }), ).resolves.toBe(true); const tampered = Uint8Array.from(payload); tampered[0] ^= 1; await expect( verifier.verify({ algorithm: "ECDSA_P256_SHA256", keyId: "image-signing-2026-01", canonicalPayload: tampered, signatureBase64Url, }), ).resolves.toBe(false); }); }); function responseAt( url: string, body: Uint8Array, init: ResponseInit, ): Response { const responseBytes = new Uint8Array(body.byteLength); responseBytes.set(body); const response = new Response(responseBytes.buffer, init); Object.defineProperty(response, "url", { configurable: false, enumerable: true, value: url, }); return response; } function publicImageHeaders( mediaType: string, contentLength?: number, ): Headers { const headers = new Headers({ "cache-control": "public, max-age=31536000, s-maxage=31536000, immutable", "content-type": mediaType, vary: "Accept-Encoding", }); if (contentLength !== undefined) { headers.set("content-length", String(contentLength)); } return headers; } function pngBytes( width: number, height: number, animated = false, ): Uint8Array { const header = new Uint8Array(13); const headerView = new DataView(header.buffer); headerView.setUint32(0, width); headerView.setUint32(4, height); header[8] = 8; header[9] = 6; return concatenateBytes([ Uint8Array.from([ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, ]), pngChunk("IHDR", header), ...(animated ? [pngChunk("acTL", new Uint8Array(8))] : []), pngChunk("IDAT", new Uint8Array()), pngChunk("IEND", new Uint8Array()), ]); } function pngChunk(type: string, payload: Uint8Array): Uint8Array { const chunk = new Uint8Array(12 + payload.byteLength); const view = new DataView(chunk.buffer); view.setUint32(0, payload.byteLength); writeAscii(chunk, 4, type); chunk.set(payload, 8); return chunk; } function jpegBytes(width: number, height: number): Uint8Array { return Uint8Array.from([ 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08, (height >>> 8) & 0xff, height & 0xff, (width >>> 8) & 0xff, width & 0xff, 0x03, 0x01, 0x11, 0x00, 0x02, 0x11, 0x00, 0x03, 0x11, 0x00, 0xff, 0xda, ]); } function webpBytes( width: number, height: number, animated = false, ): Uint8Array { const chunkType = animated ? "VP8X" : "VP8 "; const payload = new Uint8Array(10); if (animated) { payload[0] = 0x02; writeUint24LittleEndian(payload, 4, width - 1); writeUint24LittleEndian(payload, 7, height - 1); } else { payload.set([0x9d, 0x01, 0x2a], 3); const view = new DataView(payload.buffer); view.setUint16(6, width, true); view.setUint16(8, height, true); } const chunk = concatenateBytes([ asciiBytes(chunkType), littleEndianUint32(payload.byteLength), payload, ]); return concatenateBytes([ asciiBytes("RIFF"), littleEndianUint32(4 + chunk.byteLength), asciiBytes("WEBP"), chunk, ]); } function avifBytes( width: number, height: number, brand = "avif", ): Uint8Array { const fileType = isoBox( "ftyp", concatenateBytes([ asciiBytes(brand), new Uint8Array(4), asciiBytes(brand), ]), ); const spatialExtent = new Uint8Array(12); const extentView = new DataView(spatialExtent.buffer); extentView.setUint32(4, width); extentView.setUint32(8, height); const primaryItem = new Uint8Array(6); new DataView(primaryItem.buffer).setUint16(4, 1); const itemInfoEntry = new Uint8Array(13); itemInfoEntry[0] = 2; const itemInfoView = new DataView(itemInfoEntry.buffer); itemInfoView.setUint16(4, 1); writeAscii(itemInfoEntry, 8, "av01"); const itemInfo = new Uint8Array(6); new DataView(itemInfo.buffer).setUint16(4, 1); const propertyAssociation = new Uint8Array(12); const associationView = new DataView( propertyAssociation.buffer, ); associationView.setUint32(4, 1); associationView.setUint16(8, 1); propertyAssociation[10] = 1; propertyAssociation[11] = 0x81; const properties = isoBox( "iprp", concatenateBytes([ isoBox("ipco", isoBox("ispe", spatialExtent)), isoBox("ipma", propertyAssociation), ]), ); const metadata = isoBox( "meta", concatenateBytes([ new Uint8Array(4), isoBox("pitm", primaryItem), isoBox( "iinf", concatenateBytes([ itemInfo, isoBox("infe", itemInfoEntry), ]), ), properties, ]), ); return concatenateBytes([ fileType, metadata, isoBox("mdat", Uint8Array.of(0)), ]); } function isoBox(type: string, payload: Uint8Array): Uint8Array { const box = new Uint8Array(8 + payload.byteLength); const view = new DataView(box.buffer); view.setUint32(0, box.byteLength); writeAscii(box, 4, type); box.set(payload, 8); return box; } function littleEndianUint32(value: number): Uint8Array { const bytes = new Uint8Array(4); new DataView(bytes.buffer).setUint32(0, value, true); return bytes; } function writeUint24LittleEndian( bytes: Uint8Array, offset: number, value: number, ): void { bytes[offset] = value & 0xff; bytes[offset + 1] = (value >>> 8) & 0xff; bytes[offset + 2] = (value >>> 16) & 0xff; } function asciiBytes(value: string): Uint8Array { return Uint8Array.from( [...value].map((character) => character.charCodeAt(0)), ); } function writeAscii( target: Uint8Array, offset: number, value: string, ): void { target.set(asciiBytes(value), offset); } function concatenateBytes( chunks: readonly Uint8Array[], ): Uint8Array { const combined = new Uint8Array( chunks.reduce((total, chunk) => total + chunk.byteLength, 0), ); let offset = 0; for (const chunk of chunks) { combined.set(chunk, offset); offset += chunk.byteLength; } return combined; } function manualImageProbeScheduler(): Readonly<{ scheduler: ImageProbeScheduler; fire(): void; }> { let callback: (() => void) | undefined; return { scheduler: { setTimeout(nextCallback) { callback = nextCallback; return 1; }, clearTimeout: vi.fn(), }, fire() { if (!callback) { throw new TypeError("No image probe timeout is scheduled."); } callback(); }, }; } function manualCapabilityVerificationScheduler(): Readonly<{ scheduler: ImageCapabilityVerificationScheduler; delays: readonly number[]; clearTimeout: ReturnType; fire(): void; }> { let callback: (() => void) | undefined; const delays: number[] = []; const clearTimeout = vi.fn(); return { scheduler: { setTimeout(nextCallback, milliseconds) { callback = nextCallback; delays.push(milliseconds); return 1; }, clearTimeout, }, delays, clearTimeout, fire() { if (!callback) { throw new TypeError( "No capability verification timeout is scheduled.", ); } callback(); }, }; } function base64Url(bytes: Uint8Array): string { let binary = ""; for (const byte of bytes) binary += String.fromCharCode(byte); return btoa(binary) .replace(/\+/gu, "-") .replace(/\//gu, "_") .replace(/=+$/gu, ""); }