refactor: 프론트 템플릿 리펙토링

This commit is contained in:
donghyeon-ka
2026-09-18 15:16:58 +09:00
parent c10a709f2c
commit 5cc41467ae
80 changed files with 7227 additions and 4672 deletions
@@ -9,7 +9,7 @@ import {
type BrowserRpcStreamFrame,
type BrowserRpcTransport,
} from "../../../src/adapters/browser-rpc/index.ts";
import type { Result } from "../../../src/application/result.ts";
import type { Result } from "../../../src/contracts/result.ts";
import type { AppFailure } from "../../../src/contracts/errors.ts";
import {
MAPPERS,
File diff suppressed because it is too large Load Diff
+4 -104
View File
@@ -189,11 +189,11 @@ describe("CI gate contract", () => {
),
);
expect(contract.jobs).toHaveLength(9);
expect(contract.commands).toHaveLength(82);
expect(contract.gates.reduce((total, gate) => total + gate.commandIds.length, 0)).toBe(94);
expect(contract.commands).toHaveLength(84);
expect(contract.gates.reduce((total, gate) => total + gate.commandIds.length, 0)).toBe(96);
expect(contract.commands.filter(({ expect }) => expect === "fail")).toHaveLength(23);
expect(contract.gates.reduce((total, gate) => total + gate.evidenceArtifactIds.length, 0)).toBe(86);
expect(contract.artifacts).toHaveLength(107);
expect(contract.gates.reduce((total, gate) => total + gate.evidenceArtifactIds.length, 0)).toBe(88);
expect(contract.artifacts).toHaveLength(109);
expect(contract.stages).toHaveLength(5);
expect(contract.retention.classes).toHaveLength(5);
expect(index.gates.get("FE-GATE-015")?.commandIds).toHaveLength(2);
@@ -1335,106 +1335,6 @@ describe("CI gate contract", () => {
);
});
it("caps aggregate gate output at the log schema before later commands can accumulate", async () => {
const root = await mkdtemp(path.join(tmpdir(), "ci-gate-output-budget-"));
temporaryRoots.push(root);
await mkdir(path.join(root, "config/ci"), { recursive: true });
const contract = JSON.parse(JSON.stringify(await loadCiGateContract(process.cwd()))) as Record<string, any>;
const gate = contract.gates.find((entry: any) => entry.id === "FE-GATE-001");
const command = contract.commands.find((entry: any) => entry.id === gate.commandIds[0]);
command.script = "test:huge-output";
const logArtifact = contract.artifacts.find((entry: any) => entry.id === gate.logArtifactId);
const logSchema = contract.artifactSchemas.find((entry: any) => entry.id === logArtifact.schemaId);
logSchema.maxBytes = 8_192;
const packageDocument = JSON.parse(await readFile("package.json", "utf8")) as { scripts: Record<string, string> };
packageDocument.scripts["test:huge-output"] = "node -e \"process.stdout.write('x'.repeat(20000))\"";
await writeFile(path.join(root, "config/ci/gates.json"), `${JSON.stringify(contract)}\n`);
await writeFile(path.join(root, "package.json"), `${JSON.stringify(packageDocument)}\n`);
const environment = { ...process.env, CI: "false" };
const result = spawnSync(process.execPath, [path.resolve("scripts/run-ci-gate.ts"), "FE-GATE-001"], {
cwd: root,
encoding: "utf8",
env: environment,
timeout: 15_000,
});
expect(result.status).toBe(1);
const log = await readFile(path.join(root, logArtifact.path));
expect(log.byteLength).toBeLessThanOrEqual(8_192);
expect(log.toString("utf8")).toMatch(/aggregate output|INFRASTRUCTURE_FAILURE/i);
}, 20_000);
it("rejects stale command-generated evidence from a successful no-op producer", async () => {
const root = await mkdtemp(path.join(tmpdir(), "ci-gate-stale-evidence-"));
temporaryRoots.push(root);
await mkdir(path.join(root, "config/ci"), { recursive: true });
await mkdir(path.join(root, "artifacts/tests"), { recursive: true });
const contract = JSON.parse(
JSON.stringify(await loadCiGateContract(process.cwd())),
) as Record<string, any>;
const command = contract.commands.find(
(entry: Record<string, any>) => entry.id === "test-runtime-schema",
);
command.script = "test:stale-evidence-noop";
const evidence = contract.artifacts.find(
(entry: Record<string, any>) => entry.path === "artifacts/tests/runtime-schema.xml",
);
const packageDocument = JSON.parse(await readFile("package.json", "utf8")) as {
scripts: Record<string, string>;
};
packageDocument.scripts[command.script] = "true";
await writeFile(path.join(root, "config/ci/gates.json"), `${JSON.stringify(contract)}\n`);
await writeFile(path.join(root, "package.json"), `${JSON.stringify(packageDocument)}\n`);
await writeFile(
path.join(root, evidence.path),
'<testsuite name="stale" tests="0" failures="0"/>\n',
);
const result = spawnSync(
process.execPath,
[path.resolve("scripts/run-ci-gate.ts"), "FE-GATE-004"],
{ cwd: root, encoding: "utf8", env: { ...process.env, CI: "false" } },
);
expect(result.status).toBe(1);
expect(
await readFile(path.join(root, "artifacts/quality/gates/FE-GATE-004.txt"), "utf8"),
).toMatch(/not freshly produced/i);
});
it("accepts a fresh deterministic rewrite with identical evidence bytes", async () => {
const root = await mkdtemp(path.join(tmpdir(), "ci-gate-identical-rewrite-"));
temporaryRoots.push(root);
await mkdir(path.join(root, "config/ci"), { recursive: true });
await mkdir(path.join(root, "artifacts/tests"), { recursive: true });
const contract = JSON.parse(
JSON.stringify(await loadCiGateContract(process.cwd())),
) as Record<string, any>;
const command = contract.commands.find(
(entry: Record<string, any>) => entry.id === "test-runtime-schema",
);
command.script = "test:identical-evidence-rewrite";
const evidence = contract.artifacts.find(
(entry: Record<string, any>) => entry.path === "artifacts/tests/runtime-schema.xml",
);
const evidenceBytes = '<testsuite name="deterministic" tests="0" failures="0"/>\n';
const packageDocument = JSON.parse(await readFile("package.json", "utf8")) as {
scripts: Record<string, string>;
};
packageDocument.scripts[command.script] =
`node -e 'require("node:fs").writeFileSync("${evidence.path}", Buffer.from("${Buffer.from(evidenceBytes).toString("base64")}", "base64"))'`;
await writeFile(path.join(root, "config/ci/gates.json"), `${JSON.stringify(contract)}\n`);
await writeFile(path.join(root, "package.json"), `${JSON.stringify(packageDocument)}\n`);
await writeFile(path.join(root, evidence.path), evidenceBytes);
const result = spawnSync(
process.execPath,
[path.resolve("scripts/run-ci-gate.ts"), "FE-GATE-004"],
{ cwd: root, encoding: "utf8", env: { ...process.env, CI: "false" } },
);
expect(result.status).toBe(0);
expect(result.stdout).toMatch(/FE-GATE-004 runtime-schema: PASS/);
});
});
describe("CI workflow generation", () => {
+1 -1
View File
@@ -5,7 +5,7 @@ import {
isVersionCompatible,
parseNumericVersion,
verifyCompatibilityTuple,
} from "../../src/application/policies/compatibility.ts";
} from "../../src/contracts/compatibility.ts";
describe("contract compatibility", () => {
it("uses numeric version parsing rather than lexical comparison", () => {
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from "vitest";
import { createCursorPaginationRuntime } from "../../src/adapters/query-cache/cursor-pagination-runtime.ts";
import { createCursorPaginationRuntime } from "../../src/adapters/query-cache/index.ts";
const profile = {
profileId: "bounded-cursor-v1",
+48
View File
@@ -0,0 +1,48 @@
import { describe, expect, it } from "vitest";
import {
canRetryTransport,
isRetryableHttpStatus,
isRetryableSemantics,
jitteredDelay,
retryDelayFor,
} from "../../src/adapters/http/http-retry-lifecycle.ts";
describe("HTTP retry lifecycle policy", () => {
it("allows KEYED replay only before a physical dispatch", () => {
expect(canRetryTransport("KEYED", "PREPARING")).toBe(true);
expect(canRetryTransport("KEYED", "READY_TO_SEND")).toBe(true);
expect(canRetryTransport("KEYED", "DISPATCHED")).toBe(false);
expect(canRetryTransport("KEYED", "RESPONSE_HEADERS")).toBe(false);
});
it("keeps SAFE and IDEMPOTENT retryable while NEVER is terminal", () => {
expect(isRetryableSemantics("SAFE")).toBe(true);
expect(isRetryableSemantics("IDEMPOTENT")).toBe(true);
expect(isRetryableSemantics("KEYED")).toBe(false);
expect(isRetryableSemantics("NEVER")).toBe(false);
expect(canRetryTransport("SAFE", "DISPATCHED")).toBe(true);
expect(canRetryTransport("IDEMPOTENT", "READING_BODY")).toBe(true);
expect(canRetryTransport("NEVER", "PREPARING")).toBe(false);
});
it("owns the closed retryable status vocabulary", () => {
for (const status of [408, 425, 429, 502, 503, 504]) {
expect(isRetryableHttpStatus(status)).toBe(true);
}
for (const status of [400, 401, 403, 404, 409, 500, 501]) {
expect(isRetryableHttpStatus(status)).toBe(false);
}
});
it("uses bounded full jitter and rejects excessive Retry-After", () => {
expect(jitteredDelay(0, () => 0)).toBe(0);
expect(jitteredDelay(0, () => 0.5)).toBe(125);
expect(jitteredDelay(8, () => 0.5)).toBe(1_000);
expect(retryDelayFor(null, 0, () => 0.5)).toBe(125);
expect(retryDelayFor(400, 0, () => 0.5)).toBe(400);
expect(retryDelayFor(5_001, 0, () => 0.5)).toBeNull();
});
});
+652
View File
@@ -0,0 +1,652 @@
import { describe, expect, it, vi } from "vitest";
import type {
ImageProbeRequest,
} from "../../src/application/ports/browser-transfer/image-cdn.ts";
import { createBrowserImageProbe } from "../../src/adapters/browser-transfer/image-cdn/browser-image-probe.ts";
import {
avifBytes,
jpegBytes,
manualImageProbeScheduler,
pngBytes,
publicImageHeaders,
responseAt,
webpBytes,
} from "./image-cdn-test-fixture.ts";
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 });
});
});
});
@@ -0,0 +1,85 @@
import { describe, expect, it } from "vitest";
import { createP256ImageCapabilityVerifier } from "../../src/adapters/browser-transfer/image-cdn/p256-image-capability-verifier.ts";
import { base64Url } from "./image-cdn-test-fixture.ts";
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);
});
});
File diff suppressed because it is too large Load Diff
+309
View File
@@ -0,0 +1,309 @@
import { vi } from "vitest";
import type {
ImageProbeScheduler,
} from "../../src/adapters/browser-transfer/image-cdn/browser-image-probe.ts";
import type {
ImageCapabilityVerificationScheduler,
} from "../../src/adapters/browser-transfer/image-cdn/image-cdn-runtime.ts";
export 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;
}
export 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;
}
export 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;
}
export 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,
]);
}
export 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,
]);
}
export 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)),
]);
}
export 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;
}
export function littleEndianUint32(value: number): Uint8Array {
const bytes = new Uint8Array(4);
new DataView(bytes.buffer).setUint32(0, value, true);
return bytes;
}
export 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;
}
export function asciiBytes(value: string): Uint8Array {
return Uint8Array.from(
[...value].map((character) => character.charCodeAt(0)),
);
}
export function writeAscii(
target: Uint8Array,
offset: number,
value: string,
): void {
target.set(asciiBytes(value), offset);
}
export 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;
}
export 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();
},
};
}
export 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();
},
};
}
export 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, "");
}
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from "vitest";
import { createCursorPaginationRuntime } from "../../src/adapters/query-cache/cursor-pagination-runtime.ts";
import { createCursorPaginationRuntime } from "../../src/adapters/query-cache/index.ts";
import {
defineMutationIntent,
isValidIdempotencyKey,
@@ -8,8 +8,8 @@ import {
import type {
CursorPage,
CursorPaginationProfile,
} from "../../src/contracts/cursor-pagination.ts";
import type { Result } from "../../src/application/result.ts";
} from "../../src/adapters/query-cache/index.ts";
import type { Result } from "../../src/contracts/result.ts";
const PROFILE: CursorPaginationProfile = Object.freeze({
profileId: "TEST_PAGINATION_V1",
@@ -0,0 +1,420 @@
import { describe, expect, it, vi } from "vitest";
import {
BrowserFilePolicyRegistry,
browserFilePolicyReference,
} from "../../src/adapters/browser-files/browser-file-policy-registry.ts";
import {
createDownloadDeliveryAdapter,
type SaveFileHandle,
} from "../../src/adapters/browser-files/download-delivery-adapter.ts";
import {
CHECKSUM_HEADER,
CONTROL_ENDPOINT,
DATA_ORIGIN,
DIGEST_HEADER,
DOWNLOAD_HREF,
DOWNLOAD_PATH,
NOW,
POLICY_HEADER,
REQUEST_BINDING_SHA256,
UPLOAD_SESSION_ID,
collect,
createHarness,
downloadCapabilityPayload,
downloadResponse,
jsonResponse,
responseWithUrl,
uploadCapabilityPayload,
} from "./presigned-transfer-fixture.ts";
describe("presigned DownloadDelivery integration", () => {
it("connects an issued capability to DownloadDeliveryPort without caller digest input", async () => {
const bytes = new TextEncoder().encode("verified");
const payload = downloadCapabilityPayload(bytes);
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(payload)
: downloadResponse(bytes.slice().buffer, payload),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
const policy = browserFilePolicyReference(
"download",
"presigned-stream",
);
const policies = new BrowserFilePolicyRegistry({
profiles: [
{
reference: policy,
download: {
strategy: "PROMPT_AND_STREAM",
mediaType: "application/octet-stream",
safeExtension: ".bin",
maxTransferBytes: 64,
maxBufferedBytes: 8,
integrity: "REQUIRED",
},
},
],
hardLimits: {
maxInspectionBytes: 64,
maxRetainedFileBytes: 64,
maxPreviewBytes: 64,
maxObjectUrlBytes: 64,
maxTransferBytes: 64,
},
});
const written: number[] = [];
const handle: SaveFileHandle = {
async createWritable() {
return new WritableStream<Uint8Array>({
write(chunk) {
written.push(...chunk);
},
});
},
};
const downloads = createDownloadDeliveryAdapter({
host: { handoff() {} },
policies,
hardMaxObjectUrlBytes: 64,
hardMaxTransferBytes: 64,
browserManagedCapabilities: {
resolve() {
throw new TypeError("not used");
},
},
openAuthorizedSource:
executor.downloadSources.open.bind(executor.downloadSources),
showSaveFilePicker: async () => handle,
userActivation: { isActive: true },
now: () => NOW,
});
const result = await downloads.deliver({
policy,
source: {
kind: "AUTHORIZED_STREAM_RESOURCE",
resourceId: "resource-1",
capability: issued.value,
},
suggestedFileName: "artifact.bin",
signal: new AbortController().signal,
onProgress() {},
});
expect(result).toMatchObject({
ok: true,
value: {
kind: "SAVED",
integrity: "VERIFIED",
bytesWritten: bytes.byteLength,
},
});
expect(written).toEqual([...bytes]);
});
/**
* TR-RR-04. A presigned byte source owns a fetch reader and a capability
* lease, and its port requires `close()`. The delivery consumer never called
* it, so every outcome — success, validation failure, writer failure and
* abort — leaked both.
*/
it.each([
{ label: "success", mode: "SUCCESS" as const },
{ label: "writer failure", mode: "WRITER_FAILURE" as const },
{ label: "abort", mode: "ABORT" as const },
])("closes the presigned source exactly once on $label", async ({ mode }) => {
const bytes = new Uint8Array([1, 2, 3]);
let closes = 0;
const controller = new AbortController();
const source = {
byteLength: bytes.byteLength,
integrity: "VERIFIED_ON_SUCCESSFUL_EXHAUSTION" as const,
capability: undefined as never,
close() {
closes += 1;
},
async *stream() {
if (mode === "ABORT") controller.abort();
yield { ok: true as const, value: bytes };
},
};
const capability = Object.freeze({
capabilityReceipt: "capability-close-1",
method: "GET" as const,
binding: { kind: "DOWNLOAD" as const, resourceId: "resource-1" },
mediaType: "application/octet-stream",
byteLength: bytes.byteLength,
maxBytes: bytes.byteLength,
expectedSha256: "a".repeat(64),
expiresAtEpochMs: NOW + 60_000,
});
source.capability = capability as never;
const closePolicy = browserFilePolicyReference(
"download",
"presigned-close",
);
const policies = new BrowserFilePolicyRegistry({
profiles: [
{
reference: closePolicy,
download: {
strategy: "PROMPT_AND_STREAM",
mediaType: "application/octet-stream",
safeExtension: ".bin",
maxTransferBytes: 64,
maxBufferedBytes: 8,
integrity: "REQUIRED",
},
},
],
hardLimits: {
maxInspectionBytes: 64,
maxRetainedFileBytes: 64,
maxPreviewBytes: 64,
maxObjectUrlBytes: 64,
maxTransferBytes: 64,
},
});
const handle: SaveFileHandle = {
async createWritable() {
return new WritableStream<Uint8Array>({
write() {
if (mode === "WRITER_FAILURE") {
throw new TypeError("writer exploded");
}
},
});
},
};
const downloads = createDownloadDeliveryAdapter({
host: { handoff() {} },
policies,
hardMaxObjectUrlBytes: 64,
hardMaxTransferBytes: 64,
browserManagedCapabilities: {
resolve() {
throw new TypeError("not used");
},
},
openAuthorizedSource: async () =>
({ ok: true, value: source }) as never,
showSaveFilePicker: async () => handle,
userActivation: { isActive: true },
now: () => NOW,
});
const deliveryResult = await downloads.deliver({
policy: closePolicy,
source: {
kind: "AUTHORIZED_STREAM_RESOURCE",
resourceId: "resource-1",
capability: capability as never,
},
suggestedFileName: "artifact.bin",
signal: controller.signal,
onProgress() {},
});
void deliveryResult;
expect(closes).toBe(1);
});
/**
* TR-02. A lease that resolved after the abort already ended the delivery
* never reached the holder, so nothing closed it: the fetch reader and the
* capability lease outlived the terminal result.
*/
it("closes a source lease that arrives after the delivery was aborted", async () => {
const bytes = new Uint8Array([1, 2, 3]);
let closes = 0;
const controller = new AbortController();
let releaseOpen:
| ((value: { ok: true; value: unknown }) => void)
| undefined;
const source = {
byteLength: bytes.byteLength,
integrity: "VERIFIED_ON_SUCCESSFUL_EXHAUSTION" as const,
capability: undefined as never,
close() {
closes += 1;
},
async *stream() {
yield { ok: true as const, value: bytes };
},
};
const capability = Object.freeze({
capabilityReceipt: "capability-late-1",
method: "GET" as const,
binding: { kind: "DOWNLOAD" as const, resourceId: "resource-1" },
mediaType: "application/octet-stream",
byteLength: bytes.byteLength,
maxBytes: bytes.byteLength,
expectedSha256: "a".repeat(64),
expiresAtEpochMs: NOW + 60_000,
});
source.capability = capability as never;
const latePolicy = browserFilePolicyReference("download", "presigned-late");
const policies = new BrowserFilePolicyRegistry({
profiles: [
{
reference: latePolicy,
download: {
strategy: "PROMPT_AND_STREAM",
mediaType: "application/octet-stream",
safeExtension: ".bin",
maxTransferBytes: 64,
maxBufferedBytes: 8,
integrity: "REQUIRED",
},
},
],
hardLimits: {
maxInspectionBytes: 64,
maxRetainedFileBytes: 64,
maxPreviewBytes: 64,
maxObjectUrlBytes: 64,
maxTransferBytes: 64,
},
});
const downloads = createDownloadDeliveryAdapter({
host: { handoff() {} },
policies,
hardMaxObjectUrlBytes: 64,
hardMaxTransferBytes: 64,
browserManagedCapabilities: {
resolve() {
throw new TypeError("not used");
},
},
// Ignores the signal entirely and resolves only when the test says so.
openAuthorizedSource: () =>
new Promise((resolve) => {
releaseOpen = resolve as never;
}) as never,
showSaveFilePicker: async () => ({
async createWritable() {
return new WritableStream<Uint8Array>({ write() {} });
},
}),
userActivation: { isActive: true },
now: () => NOW,
});
const delivering = downloads.deliver({
policy: latePolicy,
source: {
kind: "AUTHORIZED_STREAM_RESOURCE",
resourceId: "resource-1",
capability: capability as never,
},
suggestedFileName: "artifact.bin",
signal: controller.signal,
onProgress() {},
});
await new Promise((resolve) => setTimeout(resolve, 0));
controller.abort();
const delivered = await delivering;
expect(delivered.ok).toBe(false);
// The lease arrives only now, long after the terminal result.
releaseOpen?.({ ok: true, value: source });
await new Promise((resolve) => setTimeout(resolve, 0));
expect(closes).toBe(1);
});
it("does not leave a late rejection unhandled after an abort", async () => {
const unhandled: unknown[] = [];
const onUnhandled = (reason: unknown) => unhandled.push(reason);
process.on("unhandledRejection", onUnhandled);
try {
const controller = new AbortController();
let rejectOpen: ((reason: unknown) => void) | undefined;
const rejectPolicy = browserFilePolicyReference(
"download",
"presigned-late-reject",
);
const policies = new BrowserFilePolicyRegistry({
profiles: [
{
reference: rejectPolicy,
download: {
strategy: "PROMPT_AND_STREAM",
mediaType: "application/octet-stream",
safeExtension: ".bin",
maxTransferBytes: 64,
maxBufferedBytes: 8,
integrity: "REQUIRED",
},
},
],
hardLimits: {
maxInspectionBytes: 64,
maxRetainedFileBytes: 64,
maxPreviewBytes: 64,
maxObjectUrlBytes: 64,
maxTransferBytes: 64,
},
});
const downloads = createDownloadDeliveryAdapter({
host: { handoff() {} },
policies,
hardMaxObjectUrlBytes: 64,
hardMaxTransferBytes: 64,
browserManagedCapabilities: {
resolve() {
throw new TypeError("not used");
},
},
openAuthorizedSource: () =>
new Promise((_resolve, reject) => {
rejectOpen = reject;
}) as never,
showSaveFilePicker: async () => ({
async createWritable() {
return new WritableStream<Uint8Array>({ write() {} });
},
}),
userActivation: { isActive: true },
now: () => NOW,
});
const delivering = downloads.deliver({
policy: rejectPolicy,
source: {
kind: "AUTHORIZED_STREAM_RESOURCE",
resourceId: "resource-1",
capability: Object.freeze({
capabilityReceipt: "capability-late-2",
method: "GET" as const,
binding: { kind: "DOWNLOAD" as const, resourceId: "resource-1" },
mediaType: "application/octet-stream",
byteLength: 3,
maxBytes: 3,
expectedSha256: "a".repeat(64),
expiresAtEpochMs: NOW + 60_000,
}) as never,
},
suggestedFileName: "artifact.bin",
signal: controller.signal,
onProgress() {},
});
await new Promise((resolve) => setTimeout(resolve, 0));
controller.abort();
await delivering;
rejectOpen?.(new Error("late open failure"));
await new Promise((resolve) => setTimeout(resolve, 10));
expect(unhandled).toEqual([]);
} finally {
process.off("unhandledRejection", onUnhandled);
}
});});
@@ -0,0 +1,650 @@
import { describe, expect, it, vi } from "vitest";
import { PRESIGNED_TRANSFER_PROTOCOL } from "../../src/application/ports/browser-transfer/presigned-transfer.ts";
import { createPresignedCapabilityVault } from "../../src/adapters/browser-transfer/presigned/presigned-capability-vault.ts";
import { sha256Hex } from "../../src/adapters/browser-transfer/presigned/incremental-sha256.ts";
import {
CHECKSUM_HEADER,
CONTROL_ENDPOINT,
DATA_ORIGIN,
DIGEST_HEADER,
DOWNLOAD_HREF,
DOWNLOAD_PATH,
NOW,
POLICY_HEADER,
REQUEST_BINDING_SHA256,
UPLOAD_SESSION_ID,
collect,
createHarness,
downloadCapabilityPayload,
downloadResponse,
jsonResponse,
responseWithUrl,
uploadCapabilityPayload,
} from "./presigned-transfer-fixture.ts";
describe("presigned download stream lifecycle", () => {
describe("TR-01 the stored capability is the one that was validated", () => {
const baseRegistration = () => ({
protocol: PRESIGNED_TRANSFER_PROTOCOL,
capabilityReceipt: "capability-snapshot-1",
method: "GET" as const,
binding: { kind: "DOWNLOAD" as const, resourceId: "resource-1" },
href: `${DATA_ORIGIN}${DOWNLOAD_PATH}`,
origin: DATA_ORIGIN,
path: DOWNLOAD_PATH,
allowedQueryParameters: [],
requestHeaders: [{ name: "x-safe", value: "1" }],
requiredResponseHeaders: [],
digestRequestHeader: null,
digestResponseHeader: null,
receiptResponseHeader: null,
expectedStatus: 200,
expectedResponseByteLength: 3,
mediaType: "application/octet-stream",
byteLength: 3,
maxBytes: 3,
expectedSha256: "a".repeat(64),
expiresAtEpochMs: NOW + 60_000,
});
const freshVault = () =>
createPresignedCapabilityVault({
now: () => NOW,
maxActiveCapabilities: 4,
});
it("refuses a header row that answers differently on a second read", () => {
const vault = freshVault();
let nameReads = 0;
const header = new Proxy(
{ name: "x-safe", value: "1" },
{
getOwnPropertyDescriptor(target, key) {
if (key === "name") {
nameReads += 1;
return {
configurable: true,
enumerable: true,
value: nameReads > 1 ? "authorization" : "x-safe",
};
}
return Reflect.getOwnPropertyDescriptor(target, key);
},
},
);
const registered = vault.register({
...baseRegistration(),
requestHeaders: [header],
} as never);
if (registered.ok) {
// A single read means the value that was checked is the value stored.
const resolved = vault.resolve(registered.value);
expect(resolved.ok).toBe(true);
if (resolved.ok) {
expect(resolved.value.requestHeaders.map((row) => row.name)).toEqual([
"x-safe",
]);
}
}
vault.dispose();
});
const hostileRegistrations: readonly (readonly [string, () => unknown])[] = [
[
"an accessor field",
() =>
Object.defineProperty(baseRegistration(), "href", {
enumerable: true,
get: () => `${DATA_ORIGIN}${DOWNLOAD_PATH}`,
}),
],
[
"an inherited field",
() => Object.assign(Object.create({ injected: true }), baseRegistration()),
],
[
"a symbol field",
() => ({ ...baseRegistration(), [Symbol.for("injected")]: true }),
],
[
"a non-enumerable own field",
() =>
Object.defineProperty(baseRegistration(), "injected", {
enumerable: false,
value: true,
}),
],
[
"a throwing ownKeys trap",
() =>
new Proxy(baseRegistration(), {
ownKeys() {
throw new TypeError("hostile ownKeys trap");
},
}),
],
[
"a null header array",
() => ({ ...baseRegistration(), requestHeaders: null }),
],
[
"a non-iterable header array",
() => ({ ...baseRegistration(), requestHeaders: { length: 1 } }),
],
[
"a header row with an extra field",
() => ({
...baseRegistration(),
requestHeaders: [{ name: "x-safe", value: "1", injected: true }],
}),
],
[
"an accessor header name",
() => ({
...baseRegistration(),
requestHeaders: [
Object.defineProperty({ value: "1" }, "name", {
enumerable: true,
get: () => "x-safe",
}),
],
}),
],
[
"a binding with an extra field",
() => ({
...baseRegistration(),
binding: { kind: "DOWNLOAD", resourceId: "r", injected: true },
}),
],
[
"a null binding",
() => ({ ...baseRegistration(), binding: null }),
],
];
for (const [label, build] of hostileRegistrations) {
it(`rejects ${label} as POLICY_REJECTED`, () => {
const vault = freshVault();
expect(vault.register(build() as never)).toMatchObject({
ok: false,
error: { code: "POLICY_REJECTED" },
});
vault.dispose();
});
}
it("does not observe a mutation of the issuer's object after registration", () => {
const vault = freshVault();
const registration = baseRegistration();
const registered = vault.register(registration as never);
expect(registered.ok).toBe(true);
if (!registered.ok) return;
registration.requestHeaders[0]!.name = "authorization";
registration.expiresAtEpochMs = NOW + 999_999;
const resolved = vault.resolve(registered.value);
expect(resolved.ok).toBe(true);
if (!resolved.ok) return;
expect(resolved.value.requestHeaders.map((row) => row.name)).toEqual([
"x-safe",
]);
expect(resolved.value.expiresAtEpochMs).toBe(NOW + 60_000);
vault.dispose();
});
});
it("does not fetch a presigned download until stream consumption", async () => {
const bytes = new Uint8Array([1, 2, 3]);
const responsePayload = downloadCapabilityPayload(bytes);
let downloadFetches = 0;
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(responsePayload);
}
downloadFetches += 1;
return downloadResponse(bytes.slice().buffer, responsePayload);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const signal = new AbortController().signal;
const issued = await provider.issueDownload({
resourceId: "resource-1",
signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
const opened = await executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
// BT-PRE-01. open() performs no network I/O.
expect(downloadFetches).toBe(0);
for await (const chunk of opened.value.stream(signal)) {
expect(chunk.ok).toBe(true);
}
expect(downloadFetches).toBe(1);
opened.value.close();
});
it("closes an unused download source without network I/O", async () => {
const bytes = new Uint8Array([1, 2, 3]);
const responsePayload = downloadCapabilityPayload(bytes);
let downloadFetches = 0;
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(responsePayload);
}
downloadFetches += 1;
return downloadResponse(bytes.slice().buffer, responsePayload);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const signal = new AbortController().signal;
const issued = await provider.issueDownload({
resourceId: "resource-1",
signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
const opened = await executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
opened.value.close();
// close() is idempotent and never starts the transfer.
opened.value.close();
expect(downloadFetches).toBe(0);
// A stream after close is one terminal conflict, still without fetching.
const results = [];
for await (const chunk of opened.value.stream(signal)) {
results.push(chunk);
}
expect(results).toMatchObject([
{ ok: false, error: { code: "CONFLICT" } },
]);
expect(downloadFetches).toBe(0);
});
it.each([
{
name: "truncation",
body: new Uint8Array([1, 2]),
expectedCode: "INTEGRITY_FAILED",
},
{
name: "overrun",
body: new Uint8Array([1, 2, 3, 4]),
expectedCode: "INTEGRITY_FAILED",
},
])("closes $name as a terminal stream failure", async ({ body, expectedCode }) => {
const declared = new Uint8Array([1, 2, 3]);
const payload = downloadCapabilityPayload(declared);
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(payload)
: downloadResponse(body.slice().buffer, payload),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
const opened = await executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal: new AbortController().signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
const results = await collect(opened.value);
expect(results.at(-1)).toMatchObject({
ok: false,
error: { code: expectedCode },
});
const firstFailure = results.findIndex((result) => !result.ok);
expect(results.slice(firstFailure + 1)).toEqual([]);
});
it("closes native body errors without throwing across the port", async () => {
const bytes = new Uint8Array([1, 2, 3]);
const payload = downloadCapabilityPayload(bytes);
const failingBody = new ReadableStream<Uint8Array>({
pull(controller) {
controller.error(new DOMException("secret native detail", "NetworkError"));
},
});
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(payload)
: downloadResponse(failingBody, payload),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
const opened = await executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal: new AbortController().signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
await expect(collect(opened.value)).resolves.toMatchObject([
{
ok: false,
error: {
code: "NOT_READABLE",
recovery: "REISSUE_CAPABILITY",
},
},
]);
});
it("closes active abort and timeout without leaking native rejection", async () => {
const bytes = new Uint8Array([1]);
const payload = downloadCapabilityPayload(bytes);
const neverBody = () =>
new ReadableStream<Uint8Array>({ pull() {} });
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(payload)
: downloadResponse(neverBody(), payload),
) as unknown as typeof fetch;
const controller = new AbortController();
let harness = createHarness({ fetcher });
let issued = await harness.provider.issueDownload({
resourceId: "resource-1",
signal: controller.signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
let opened = await harness.executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal: controller.signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
const aborted = collect(opened.value, controller.signal);
controller.abort("user");
expect(await aborted).toMatchObject([
{ ok: false, error: { code: "ABORTED" } },
]);
let timeoutCallback: (() => void) | undefined;
const scheduler = {
setTimeout(callback: () => void) {
timeoutCallback = callback;
return 1;
},
clearTimeout() {},
};
harness = createHarness({ fetcher, scheduler });
issued = await harness.provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
opened = await harness.executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal: new AbortController().signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
const timedOut = collect(opened.value);
timeoutCallback?.();
expect(await timedOut).toMatchObject([
{
ok: false,
error: {
code: "UNAVAILABLE",
recovery: "REISSUE_CAPABILITY",
},
},
]);
});
it("rejects an expired capability before data-plane fetch", async () => {
const bytes = new Uint8Array([1]);
const payload = downloadCapabilityPayload(bytes);
let current = NOW;
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(payload)
: downloadResponse(bytes.slice().buffer, payload),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({
fetcher,
now: () => current,
});
const issued = await provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
current = Number(payload.expiresAtEpochMs) + 1;
expect(
await executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: {
code: "EXPIRED_RESOURCE",
recovery: "REISSUE_CAPABILITY",
},
});
expect(fetcher).toHaveBeenCalledTimes(1);
});
it("rejects capabilities below the configured minimum remaining lifetime", async () => {
const bytes = new Uint8Array([1]);
const nearExpiryPayload = downloadCapabilityPayload(bytes, {
expiresAtEpochMs: NOW + 999,
});
let fetcher = vi.fn(async () =>
jsonResponse(nearExpiryPayload),
) as unknown as typeof fetch;
let harness = createHarness({ fetcher });
expect(
await harness.provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: {
code: "EXPIRED_RESOURCE",
recovery: "REISSUE_CAPABILITY",
},
});
const acceptedPayload = downloadCapabilityPayload(bytes, {
expiresAtEpochMs: NOW + 2_000,
});
let current = NOW;
fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(acceptedPayload)
: downloadResponse(bytes.slice().buffer, acceptedPayload),
) as unknown as typeof fetch;
harness = createHarness({
fetcher,
now: () => current,
});
const issued = await harness.provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
current = NOW + 1_001;
expect(
await harness.executor.downloadSources.open({
resourceId: "resource-1",
capability: issued.value,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: {
code: "EXPIRED_RESOURCE",
recovery: "REISSUE_CAPABILITY",
},
});
expect(fetcher).toHaveBeenCalledTimes(1);
});
it("closes malformed AbortSignal inputs at every public boundary", async () => {
const bytes = new Uint8Array([1, 2]);
const payload = downloadCapabilityPayload(bytes);
const uploadChecksum = sha256Hex(bytes);
const uploadPayload = uploadCapabilityPayload({
bytes,
checksum: uploadChecksum,
});
const fetcher = vi.fn(
async (input: RequestInfo | URL, init?: RequestInit) => {
if (String(input) === CONTROL_ENDPOINT) {
const request = JSON.parse(String(init?.body)) as {
method: string;
};
return jsonResponse(
request.method === "GET" ? payload : uploadPayload,
);
}
if (String(input) === DOWNLOAD_HREF) {
return downloadResponse(bytes.slice().buffer, payload);
}
return responseWithUrl(
new Response(null, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "0",
ETag: "\"part-etag-1\"",
},
}),
String(uploadPayload.href),
);
},
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const malformed = {} as AbortSignal;
expect(
await provider.issueDownload({
resourceId: "resource-1",
signal: malformed,
}),
).toMatchObject({
ok: false,
error: { code: "INVALID_INPUT" },
});
expect(
await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: uploadChecksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: malformed,
}),
).toMatchObject({
ok: false,
error: { code: "INVALID_INPUT" },
});
const issuedDownload = await provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issuedDownload.ok).toBe(true);
if (!issuedDownload.ok) return;
expect(
await executor.downloadSources.open({
resourceId: "resource-1",
capability: issuedDownload.value,
signal: malformed,
}),
).toMatchObject({
ok: false,
error: { code: "INVALID_INPUT" },
});
const opened = await executor.downloadSources.open({
resourceId: "resource-1",
capability: issuedDownload.value,
signal: new AbortController().signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
expect(await collect(opened.value, malformed)).toMatchObject([
{ ok: false, error: { code: "INVALID_INPUT" } },
]);
expect(await collect(opened.value)).toMatchObject([
{ ok: false, error: { code: "CONFLICT" } },
]);
const issuedUpload = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: uploadChecksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issuedUpload.ok).toBe(true);
if (!issuedUpload.ok) return;
expect(
await executor.uploadParts.put({
capability: issuedUpload.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: uploadChecksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: malformed,
}),
).toMatchObject({
ok: false,
error: { code: "INVALID_INPUT" },
});
});
});
+247
View File
@@ -0,0 +1,247 @@
import { PRESIGNED_TRANSFER_PROTOCOL } from "../../src/application/ports/browser-transfer/presigned-transfer.ts";
import type {
PresignedDownloadByteSource,
} from "../../src/application/ports/browser-transfer/presigned-transfer.ts";
import { RESUMABLE_UPLOAD_PROTOCOL } from "../../src/application/ports/browser-transfer/resumable-upload.ts";
import type { BrowserDataObservation } from "../../src/application/ports/browser-file-storage/shared.ts";
import {
createPresignedCapabilityVault,
createSingleUsePresignedReplayGuard,
} from "../../src/adapters/browser-transfer/presigned/presigned-capability-vault.ts";
import { createPresignedCapabilityHttpProvider } from "../../src/adapters/browser-transfer/presigned/presigned-capability-http-provider.ts";
import {
createPresignedTransferExecutor,
type PresignedTransferExecutorOptions,
} from "../../src/adapters/browser-transfer/presigned/presigned-transfer-executor.ts";
import { sha256Hex } from "../../src/adapters/browser-transfer/presigned/incremental-sha256.ts";
export const NOW = 1_000_000;
export const CONTROL_ENDPOINT = "https://api.example/capabilities";
export const DATA_ORIGIN = "https://objects.example";
export const DOWNLOAD_PATH = "/files/resource-1";
export const DOWNLOAD_HREF =
`${DATA_ORIGIN}${DOWNLOAD_PATH}?sig=do-not-log-this`;
export const POLICY_HEADER = "x-policy-version";
export const DIGEST_HEADER = "x-content-sha256";
export const CHECKSUM_HEADER = "x-checksum-sha256";
export const UPLOAD_SESSION_ID = "upload-session-1";
export const REQUEST_BINDING_SHA256 = "c".repeat(64);
export function downloadCapabilityPayload(
bytes: Uint8Array,
overrides: Readonly<Record<string, unknown>> = {},
) {
const digest = sha256Hex(bytes);
return {
protocol: PRESIGNED_TRANSFER_PROTOCOL,
capabilityReceipt: "capability-download-1",
method: "GET",
binding: {
kind: "DOWNLOAD",
resourceId: "resource-1",
},
href: DOWNLOAD_HREF,
origin: DATA_ORIGIN,
path: DOWNLOAD_PATH,
allowedQueryParameters: ["sig"],
requestHeaders: [
{ name: "accept", value: "application/octet-stream" },
],
requiredResponseHeaders: [
{ name: POLICY_HEADER, value: "v1" },
],
digestRequestHeader: null,
digestResponseHeader: DIGEST_HEADER,
receiptResponseHeader: null,
expectedStatus: 200,
expectedResponseByteLength: null,
mediaType: "application/octet-stream",
byteLength: bytes.byteLength,
maxBytes: 64,
expectedSha256: digest,
expiresAtEpochMs: NOW + 30_000,
singleUse: true,
...overrides,
};
}
export type CapabilityPayload = ReturnType<typeof downloadCapabilityPayload>;
export function uploadCapabilityPayload(input: Readonly<{
bytes: Uint8Array;
checksum: string;
}>, overrides: Readonly<Record<string, unknown>> = {}) {
return {
protocol: PRESIGNED_TRANSFER_PROTOCOL,
capabilityReceipt: "capability-upload-1",
method: "PUT",
binding: {
kind: "UPLOAD_PART",
protocol: RESUMABLE_UPLOAD_PROTOCOL,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
idempotencyKey: "part-attempt-1",
},
href: `${DATA_ORIGIN}/uploads/session-1/part-1?sig=secret`,
origin: DATA_ORIGIN,
path: "/uploads/session-1/part-1",
allowedQueryParameters: ["sig"],
requestHeaders: [
{ name: "content-type", value: "application/octet-stream" },
{ name: CHECKSUM_HEADER, value: input.checksum },
],
requiredResponseHeaders: [
{ name: POLICY_HEADER, value: "v1" },
],
digestRequestHeader: CHECKSUM_HEADER,
digestResponseHeader: null,
receiptResponseHeader: "etag",
expectedStatus: 200,
expectedResponseByteLength: 0,
mediaType: "application/octet-stream",
byteLength: input.bytes.byteLength,
maxBytes: 64,
expectedSha256: input.checksum,
expiresAtEpochMs: NOW + 30_000,
singleUse: true,
...overrides,
};
}
export function jsonResponse(
value: unknown,
url = CONTROL_ENDPOINT,
): Response {
return responseWithUrl(
new Response(JSON.stringify(value), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
url,
);
}
export function downloadResponse(
body: BodyInit | null,
payload: CapabilityPayload,
headers: Record<string, string> = {},
): Response {
return responseWithUrl(
new Response(body, {
status: payload.expectedStatus as number,
headers: {
"Content-Type": String(payload.mediaType),
"Content-Length": String(payload.byteLength),
[DIGEST_HEADER]: String(payload.expectedSha256),
[POLICY_HEADER]: "v1",
...headers,
},
}),
String(payload.href),
);
}
export function responseWithUrl(response: Response, href: string): Response {
Object.defineProperty(response, "url", {
configurable: true,
value: href,
});
return response;
}
export function createHarness(input: Readonly<{
fetcher: typeof fetch;
maxActiveCapabilities?: number;
now?: () => number;
digestBytes?: PresignedTransferExecutorOptions["digestBytes"];
scheduler?: PresignedTransferExecutorOptions["scheduler"];
observer?: Readonly<{
record(observation: BrowserDataObservation): void;
}>;
}>) {
const now = input.now ?? (() => NOW);
const vault = createPresignedCapabilityVault({
maxActiveCapabilities: input.maxActiveCapabilities ?? 16,
now,
});
const replayGuard = createSingleUsePresignedReplayGuard();
const provider = createPresignedCapabilityHttpProvider({
endpoint: CONTROL_ENDPOINT,
vault,
allowedDataOrigins: [DATA_ORIGIN],
allowedDataPathPrefixes: ["/files/", "/uploads/"],
allowedQueryParameters: ["sig"],
allowedRequestHeaders: [
"accept",
"content-type",
CHECKSUM_HEADER,
],
allowedResponseHeaders: [
POLICY_HEADER,
DIGEST_HEADER,
"etag",
],
hardMaxTransferBytes: 64,
hardMaxUploadResponseBytes: 16,
maxCapabilityTtlMs: 60_000,
minimumRemainingLifetimeMs: 1_000,
timeoutMs: 5_000,
fetcher: input.fetcher,
now,
scheduler: input.scheduler,
observer: input.observer,
});
const executor = createPresignedTransferExecutor({
vault,
replayGuard,
hardMaxTransferBytes: 64,
hardMaxChunkBytes: 2,
hardMaxUploadResponseBytes: 16,
minimumRemainingLifetimeMs: 1_000,
timeoutMs: 5_000,
fetcher: input.fetcher,
now,
scheduler: input.scheduler,
digestBytes: input.digestBytes,
observer: input.observer,
});
return { provider, executor, vault };
}
export async function collect(
source: PresignedDownloadByteSource,
signal = new AbortController().signal,
) {
const results = [];
for await (const result of source.stream(signal)) {
results.push(result);
}
return results;
}
/**
* BT-PRE-01. The download lease is lazy, so a response-shape rejection is
* observed on first consumption rather than at open().
*/
export async function firstStreamResult(
opened: Awaited<
ReturnType<
ReturnType<typeof createHarness>["executor"]["downloadSources"]["open"]
>
>,
): Promise<unknown> {
if (!opened.ok) return opened;
try {
for await (const chunk of opened.value.stream(
new AbortController().signal,
)) {
if (!chunk.ok) return chunk;
}
return { ok: true };
} finally {
opened.value.close();
}
}
@@ -0,0 +1,549 @@
import { describe, expect, it, vi } from "vitest";
import type { BrowserDataObservation } from "../../src/application/ports/browser-file-storage/shared.ts";
import { sha256Hex } from "../../src/adapters/browser-transfer/presigned/incremental-sha256.ts";
import {
CHECKSUM_HEADER,
CONTROL_ENDPOINT,
DATA_ORIGIN,
DIGEST_HEADER,
DOWNLOAD_HREF,
DOWNLOAD_PATH,
NOW,
POLICY_HEADER,
REQUEST_BINDING_SHA256,
UPLOAD_SESSION_ID,
collect,
createHarness,
downloadCapabilityPayload,
downloadResponse,
jsonResponse,
responseWithUrl,
uploadCapabilityPayload,
} from "./presigned-transfer-fixture.ts";
describe("presigned upload part execution", () => {
it("snapshots, verifies and uploads a PUT part with a separate response receipt", async () => {
const original = new Uint8Array([9, 8, 7]);
const checksum = sha256Hex(original);
const payload = uploadCapabilityPayload({
bytes: original,
checksum,
});
let releaseDigest: (() => void) | undefined;
const digestGate = new Promise<void>((resolve) => {
releaseDigest = resolve;
});
const sentBodies: number[][] = [];
const dataCalls: RequestInit[] = [];
const fetcher = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
if (String(input) === CONTROL_ENDPOINT) return jsonResponse(payload);
dataCalls.push(init ?? {});
sentBodies.push([
...new Uint8Array(init?.body as ArrayBuffer),
]);
return responseWithUrl(
new Response(null, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "0",
ETag: "\"part-etag-1\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({
fetcher,
digestBytes: async (bytes) => {
await digestGate;
return sha256Hex(bytes);
},
});
const issued = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: original.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
const request = {
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: original.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes: original,
signal: new AbortController().signal,
};
const pending = executor.uploadParts.put(request);
original.fill(0);
request.sessionId = "mutated-session";
request.requestBindingSha256 = "d".repeat(64);
request.checksumSha256 = "f".repeat(64);
releaseDigest?.();
expect(await pending).toEqual({
ok: true,
value: {
bytesWritten: 3,
checksumSha256: checksum,
receiptToken: "part-etag-1",
},
});
expect(sentBodies).toEqual([[9, 8, 7]]);
expect(dataCalls[0]).toMatchObject({
method: "PUT",
credentials: "omit",
redirect: "error",
referrerPolicy: "no-referrer",
});
expect(
(dataCalls[0]?.headers as Headers).get(CHECKSUM_HEADER),
).toBe(checksum);
});
it.each(["sessionId", "requestBindingSha256"] as const)(
"rejects an actual PUT whose %s differs from the capability",
async (field) => {
const bytes = new Uint8Array([3, 2, 1]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload({ bytes, checksum });
const fetcher = vi.fn(async () =>
jsonResponse(payload),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId:
field === "sessionId"
? "different-session"
: UPLOAD_SESSION_ID,
requestBindingSha256:
field === "requestBindingSha256"
? "d".repeat(64)
: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: { code: "POLICY_REJECTED" },
});
expect(fetcher).toHaveBeenCalledTimes(1);
},
);
it("rejects URL-shaped upload receipts", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload({ bytes, checksum });
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(payload);
}
return responseWithUrl(
new Response(null, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "0",
ETag: "\"https://objects.example/authorizing-token\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: { code: "INTEGRITY_FAILED" },
});
});
it("drains a bounded successful PUT acknowledgement without cancelling it", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload(
{ bytes, checksum },
{ expectedResponseByteLength: 2 },
);
let cancelled = false;
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(payload);
}
const body = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new Uint8Array([8, 9]));
controller.close();
},
cancel() {
cancelled = true;
},
});
return responseWithUrl(
new Response(body, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "2",
ETag: "\"part-etag-1\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: true,
value: { receiptToken: "part-etag-1" },
});
expect(cancelled).toBe(false);
});
it("accepts an empty 204 PUT acknowledgement", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload(
{ bytes, checksum },
{
expectedStatus: 204,
expectedResponseByteLength: 0,
},
);
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(payload)
: responseWithUrl(
new Response(null, {
status: 204,
headers: {
[POLICY_HEADER]: "v1",
ETag: "\"part-etag-204\"",
},
}),
String(payload.href),
),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: true,
value: { receiptToken: "part-etag-204" },
});
});
it("cancels a PUT acknowledgement whose declared length violates its binding", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload({ bytes, checksum });
let cancelled = false;
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(payload);
}
const body = new ReadableStream<Uint8Array>({
pull() {},
cancel() {
cancelled = true;
},
});
return responseWithUrl(
new Response(body, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "1",
ETag: "\"part-etag-1\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: { code: "POLICY_REJECTED" },
});
expect(cancelled).toBe(true);
});
it("observes only safe operation, outcome, failure and byte buckets", async () => {
const bytes = new Uint8Array([7, 8, 9]);
const downloadPayload = downloadCapabilityPayload(bytes);
const checksum = sha256Hex(bytes);
const uploadPayload = uploadCapabilityPayload({ bytes, checksum });
const observations: BrowserDataObservation[] = [];
const fetcher = vi.fn(
async (input: RequestInfo | URL, init?: RequestInit) => {
if (String(input) === CONTROL_ENDPOINT) {
const request = JSON.parse(String(init?.body)) as {
method: string;
};
return jsonResponse(
request.method === "GET"
? downloadPayload
: uploadPayload,
);
}
if (String(input) === DOWNLOAD_HREF) {
return downloadResponse(
bytes.slice().buffer,
downloadPayload,
);
}
return responseWithUrl(
new Response(null, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "0",
ETag: "\"part-etag-secret\"",
},
}),
String(uploadPayload.href),
);
},
) as unknown as typeof fetch;
const { provider, executor } = createHarness({
fetcher,
observer: {
record(observation) {
observations.push(observation);
},
},
});
const issuedDownload = await provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issuedDownload.ok).toBe(true);
if (!issuedDownload.ok) return;
const opened = await executor.downloadSources.open({
resourceId: "resource-1",
capability: issuedDownload.value,
signal: new AbortController().signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
expect((await collect(opened.value)).every((result) => result.ok)).toBe(
true,
);
const issuedUpload = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issuedUpload.ok).toBe(true);
if (!issuedUpload.ok) return;
expect(
await executor.uploadParts.put({
capability: issuedUpload.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({ ok: true });
expect(observations).toEqual([
{
operation: "PRESIGNED_TRANSFER",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "PRESIGNED_TRANSFER",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "DOWNLOAD",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "PRESIGNED_TRANSFER",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "UPLOAD_PART",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
]);
const serialized = JSON.stringify(observations);
for (const secret of [
DOWNLOAD_HREF,
"do-not-log-this",
checksum,
"capability-download-1",
"capability-upload-1",
"part-etag-secret",
"resource-1",
]) {
expect(serialized).not.toContain(secret);
}
});
});
File diff suppressed because it is too large Load Diff
-30
View File
@@ -965,36 +965,6 @@ describe("security follow-up contracts", () => {
await expect(running).rejects.toThrow(/timed out.*kill failed.*close/u);
});
it("kills and reaps a stubborn provider process group including its descendant", async () => {
const root = await mkdtemp(path.join(tmpdir(), "provider-process-group-"));
const descendantPidPath = path.join(root, "descendant.pid");
try {
const source = [
"const { spawn } = require('node:child_process');",
"const { writeFileSync } = require('node:fs');",
"const child = spawn(process.execPath, ['-e', `process.on('SIGTERM', () => {}); setInterval(() => {}, 1000)`], { stdio: 'ignore' });",
"writeFileSync(process.env.DESCENDANT_PID_PATH, String(child.pid));",
"process.on('SIGTERM', () => {});",
"setInterval(() => {}, 1000);",
].join("\n");
const running = runProviderProcess({
executable: process.execPath,
arguments: ["-e", source],
environment: {
PATH: process.env.PATH,
DESCENDANT_PID_PATH: descendantPidPath,
},
timeoutMs: 250,
});
await expect(running).rejects.toThrow(/timed out.*process close/u);
const descendantPid = Number(await readFile(descendantPidPath, "utf8"));
expect(Number.isSafeInteger(descendantPid) && descendantPid > 0).toBe(true);
expect(() => process.kill(descendantPid, 0)).toThrow(/ESRCH|no such process/u);
} finally {
await rm(root, { recursive: true, force: true });
}
});
it.each(["open failure", "partial write failure"])(
"cleans finalized staging from memory when GITHUB_OUTPUT has a %s",
async (failureKind) => {
@@ -182,9 +182,9 @@ describe("selective Task 3 contract closure", () => {
it.skipIf(isReducedCiContractRun())("accepts only the canonical exact-count authority and rejects orphan retention", async () => {
const canonical = await loadCiGateContract(process.cwd());
expect(canonical.gates).toHaveLength(27);
expect(canonical.commands).toHaveLength(82);
expect(canonical.gates.reduce((sum, gate) => sum + gate.commandIds.length, 0)).toBe(94);
expect(canonical.artifacts).toHaveLength(107);
expect(canonical.commands).toHaveLength(84);
expect(canonical.gates.reduce((sum, gate) => sum + gate.commandIds.length, 0)).toBe(96);
expect(canonical.artifacts).toHaveLength(109);
expect(canonical.stages).toHaveLength(5);
expect(canonical.retention.classes).toHaveLength(5);