Files
clean-architecture-frontend…/tests/unit/image-cdn-runtime.test.ts
T
DongHyeonkaandClaude Opus 5 cc91fc6ae0 fix: settle a shared abort operation by observation, not by drain count
The primitive decided a raced outcome by draining a hard-coded four
microtasks and then asking whether the task had landed. That made the
answer depend on scheduling rather than on what was observed: a caller
abort could fix the terminal owner synchronously and a rejection later in
the same call stack still won the public result, so `race()` disagreed
with `terminal()` and the failure taxonomy a caller received depended on
microtask ordering.

Task settlement and the terminal event now share one settle-once state
machine. Whichever callback actually runs first owns the outcome; a value
that loses is compensated exactly once and a rejection that loses is
absorbed, so neither can surface late.

The three consumers that kept their own copies of these mechanics move
onto it. The Image probe and the Resumable fetch transport attached their
caller listener before installing the timer, so a scheduler that threw
rejected the public `probe()`/`execute()` promise natively and left the
listener on the caller's signal; both now close atomically inside their
own Result vocabulary and start no fetch. `snapshotAbortTimers` binds the
scheduler callables once at construction, so replacing a method after
composition can no longer change how work already in flight is bounded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 01:24:53 +09:00

2431 lines
68 KiB
TypeScript

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> = {},
): 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> = {},
): 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<BackendIssuedImageAsset> = {},
): Promise<BackendIssuedImageAsset> {
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<PublicImmutableImageAsset>),
),
).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<typeof runtime.presentation.resolve>[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<ImageCdnHardLimits>[] = [
{ 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<string>(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<boolean>((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<string, unknown>[] = [];
const verifierDeadline =
manualCapabilityVerificationScheduler();
const stalledVerifier = vi.fn(
() => new Promise<boolean>(() => 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<ArrayBuffer>(() => 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<boolean>(() => 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<boolean>((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<boolean>(() => 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<never>(() => 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<string, unknown>[] = [];
const observer = {
record(observation: Record<string, unknown>) {
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> = {},
): 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<ImageProbeRequest>),
),
).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<ReadableStreamReadResult<Uint8Array>>(
() => 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<typeof vi.fn>;
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, "");
}