Files
tech-log-frontend/tests/browser-capabilities/presigned-streaming.spec.ts
T
DongHyeonkaandClaude Opus 5 bdee07a93b chore: sync the frontend template from a0fbafb to 5434760
Carries eight template commits: the provider sandbox actually running, release
admission to a named environment, the product feature manifest with its runtime
kill switch, architecture and documentation rules that match what is enforced,
the removability fixtures, and the browser, visual and performance evidence.

Product identity is unchanged. `package.json` keeps `tech-log-frontend` and the
catalog keeps the Tech Log naming; the home page was not in the delta. The
visual baselines are this product's own — the template's were excluded from the
transplant and these were regenerated here, where the only difference is the
platform overview's new product-feature section.

What this repository gains operationally: `config/runtime/{local,development,
staging,production}.json` with `FE-GATE-027` refusing an artifact whose runtime
document does not match the environment it is being admitted to, and
`FEATURE_OVERRIDES` for taking an installed feature out of service without a
rebuild.

Verified here: eight gates green, build green, visual 5/5, and 1,858 of 1,859
tests in the suites that do not need a sandbox — the one failure passes in
isolation and is a jsdom lazy-chunk timeout under parallel load. The provider
suites cannot run on this machine at all: `kernel.apparmor_restrict_unprivileged
_userns=1` makes `bwrap --unshare-net` fail, reproducible without any code from
either repository.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 21:34:19 +09:00

376 lines
11 KiB
TypeScript

import { createHash } from "node:crypto";
import { expect, test } from "../support/browser/strict-browser-test.ts";
const RESOURCE_ID = "browser-artifact-1";
const OBJECT_ORIGIN = "https://objects.example.test";
const OBJECT_PATH = "/files/browser-artifact-1";
const OBJECT_HREF =
`${OBJECT_ORIGIN}${OBJECT_PATH}?sig=opaque-browser-signature`;
const DOWNLOAD_BYTES = Buffer.from([
0x10, 0x20, 0x30, 0x40, 0x50,
0x60, 0x70, 0x80, 0x90, 0xa0,
]);
const DOWNLOAD_SHA256 = createHash("sha256")
.update(DOWNLOAD_BYTES)
.digest("hex");
test("issues an opaque capability and streams a verified object into the writable save path", async ({
page,
}) => {
const bffRequests: unknown[] = [];
const objectRequests: Readonly<{
url: string;
method: string;
accept: string | undefined;
cookie: string | undefined;
}>[] = [];
await page.route("**/api/download-capability", async (route) => {
bffRequests.push(route.request().postDataJSON());
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
// The wire envelope names the protocol it speaks. Without it the
// capability is refused before any object request is made, so the whole
// download path below was asserting on an empty transcript.
protocol: "PRESIGNED_TRANSFER_V1",
capabilityReceipt: "browser-download-capability-1",
method: "GET",
binding: {
kind: "DOWNLOAD",
resourceId: RESOURCE_ID,
},
href: OBJECT_HREF,
origin: OBJECT_ORIGIN,
path: OBJECT_PATH,
allowedQueryParameters: ["sig"],
requestHeaders: [
{
name: "accept",
value: "application/octet-stream",
},
],
requiredResponseHeaders: [
{
name: "x-policy-version",
value: "v1",
},
],
digestRequestHeader: null,
digestResponseHeader: "x-content-sha256",
receiptResponseHeader: null,
expectedStatus: 200,
expectedResponseByteLength: null,
mediaType: "application/octet-stream",
byteLength: DOWNLOAD_BYTES.byteLength,
maxBytes: 64,
expectedSha256: DOWNLOAD_SHA256,
expiresAtEpochMs: Date.now() + 5 * 60_000,
singleUse: true,
}),
});
});
await page.route(`${OBJECT_ORIGIN}/**`, async (route) => {
const headers = route.request().headers();
objectRequests.push({
url: route.request().url(),
method: route.request().method(),
accept: headers.accept,
cookie: headers.cookie,
});
await route.fulfill({
status: 200,
body: DOWNLOAD_BYTES,
headers: {
"access-control-allow-origin": "*",
"access-control-expose-headers":
"content-length, x-content-sha256, x-policy-version",
"content-length": String(DOWNLOAD_BYTES.byteLength),
"content-type": "application/octet-stream",
"x-content-sha256": DOWNLOAD_SHA256,
"x-policy-version": "v1",
},
});
});
await page.goto("/");
const result = await page.evaluate(
async ({ resourceId }) => {
const vaultModulePath =
"/src/adapters/browser-transfer/presigned/presigned-capability-vault.ts";
const providerModulePath =
"/src/adapters/browser-transfer/presigned/presigned-capability-http-provider.ts";
const executorModulePath =
"/src/adapters/browser-transfer/presigned/presigned-transfer-executor.ts";
const policyModulePath =
"/src/adapters/browser-files/browser-file-policy-registry.ts";
const deliveryModulePath =
"/src/adapters/browser-files/download-delivery-adapter.ts";
const [
{
createPresignedCapabilityVault,
createSingleUsePresignedReplayGuard,
},
{ createPresignedCapabilityHttpProvider },
{ createPresignedTransferExecutor },
{
BrowserFilePolicyRegistry,
browserFilePolicyReference,
},
{ createDownloadDeliveryAdapter },
] = await Promise.all([
import(
/* @vite-ignore */ vaultModulePath
) as Promise<
typeof import("../../src/adapters/browser-transfer/presigned/presigned-capability-vault.ts")
>,
import(
/* @vite-ignore */ providerModulePath
) as Promise<
typeof import("../../src/adapters/browser-transfer/presigned/presigned-capability-http-provider.ts")
>,
import(
/* @vite-ignore */ executorModulePath
) as Promise<
typeof import("../../src/adapters/browser-transfer/presigned/presigned-transfer-executor.ts")
>,
import(
/* @vite-ignore */ policyModulePath
) as Promise<
typeof import("../../src/adapters/browser-files/browser-file-policy-registry.ts")
>,
import(
/* @vite-ignore */ deliveryModulePath
) as Promise<
typeof import("../../src/adapters/browser-files/download-delivery-adapter.ts")
>,
]);
const vault = createPresignedCapabilityVault({
maxActiveCapabilities: 4,
});
const provider = createPresignedCapabilityHttpProvider({
endpoint: `${location.origin}/api/download-capability`,
vault,
allowedDataOrigins: ["https://objects.example.test"],
allowedDataPathPrefixes: ["/files/"],
allowedQueryParameters: ["sig"],
allowedRequestHeaders: ["accept"],
allowedResponseHeaders: [
"x-content-sha256",
"x-policy-version",
],
hardMaxTransferBytes: 64,
hardMaxUploadResponseBytes: 1_024,
maxCapabilityTtlMs: 10 * 60_000,
minimumRemainingLifetimeMs: 30_000,
timeoutMs: 5_000,
allowInsecureLocalhost: true,
});
const executor = createPresignedTransferExecutor({
vault,
replayGuard: createSingleUsePresignedReplayGuard(),
hardMaxTransferBytes: 64,
hardMaxChunkBytes: 3,
hardMaxUploadResponseBytes: 1_024,
minimumRemainingLifetimeMs: 30_000,
timeoutMs: 5_000,
});
const signal = new AbortController().signal;
const issued = await provider.issueDownload({
resourceId,
signal,
});
if (!issued.ok) {
vault.dispose();
return {
issued,
delivery: null,
capabilityKeys: [],
capabilityBindingKeys: [],
written: [],
writeChunkSizes: [],
writableClosed: false,
writableAborted: false,
progressPhases: [],
};
}
const downloadPolicy = browserFilePolicyReference(
"browser-presigned-download",
"save-verified-artifact",
);
const policies = new BrowserFilePolicyRegistry({
profiles: [
{
reference: downloadPolicy,
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 writeChunkSizes: number[] = [];
let writableClosed = false;
let writableAborted = false;
const downloads = createDownloadDeliveryAdapter({
host: {
handoff() {
throw new TypeError(
"Writable delivery must not use browser handoff.",
);
},
},
policies,
hardMaxObjectUrlBytes: 64,
hardMaxTransferBytes: 64,
browserManagedCapabilities: {
resolve() {
throw new TypeError(
"Browser-managed capability is not used.",
);
},
},
openAuthorizedSource:
executor.downloadSources.open.bind(
executor.downloadSources,
),
showSaveFilePicker: async () => ({
async createWritable() {
return new WritableStream<Uint8Array>({
write(chunk) {
writeChunkSizes.push(chunk.byteLength);
written.push(...chunk);
},
close() {
writableClosed = true;
},
abort() {
writableAborted = true;
},
});
},
}),
createTransferId: () => "transfer:browser-presigned",
progressMinIntervalMs: 0,
userActivation: { isActive: true },
});
const progressPhases: string[] = [];
const capabilityKeys = Object.keys(issued.value).sort();
const capabilityBindingKeys = Object.keys(
issued.value.binding,
).sort();
const delivery = await downloads.deliver({
policy: downloadPolicy,
source: {
kind: "AUTHORIZED_STREAM_RESOURCE",
resourceId,
capability: issued.value,
},
suggestedFileName: "browser-artifact.bin",
signal,
onProgress(progress) {
progressPhases.push(progress.phase);
},
});
downloads.dispose();
vault.dispose();
return {
issued: {
ok: true as const,
exposedHref: "href" in issued.value,
exposedRequestHeaders: "requestHeaders" in issued.value,
},
delivery,
capabilityKeys,
capabilityBindingKeys,
written,
writeChunkSizes,
writableClosed,
writableAborted,
progressPhases,
};
},
{ resourceId: RESOURCE_ID },
);
expect(bffRequests).toEqual([
{
// The capability request names the protocol it is asking for. Leaving it
// out of this expectation meant the fixture stopped describing the
// request the adapter actually sends when PRESIGNED_TRANSFER_V1 was
// hardened, and the object GET path stopped being exercised at all.
protocol: "PRESIGNED_TRANSFER_V1",
method: "GET",
binding: {
kind: "DOWNLOAD",
resourceId: RESOURCE_ID,
},
},
]);
expect(objectRequests).toEqual([
{
url: OBJECT_HREF,
method: "GET",
accept: "application/octet-stream",
cookie: undefined,
},
]);
expect(result.issued).toEqual({
ok: true,
exposedHref: false,
exposedRequestHeaders: false,
});
expect(result.capabilityKeys).toEqual([
"binding",
"byteLength",
"capabilityReceipt",
"expectedSha256",
"expiresAtEpochMs",
"maxBytes",
"mediaType",
"method",
]);
expect(result.capabilityBindingKeys).toEqual([
"kind",
"resourceId",
]);
expect(result.delivery).toEqual({
ok: true,
value: {
kind: "SAVED",
transferId: "transfer:browser-presigned",
bytesWritten: DOWNLOAD_BYTES.byteLength,
integrity: "VERIFIED",
},
});
expect(result.written).toEqual([...DOWNLOAD_BYTES]);
expect(result.writeChunkSizes).toEqual([3, 3, 3, 1]);
expect(result.writableClosed).toBe(true);
expect(result.writableAborted).toBe(false);
expect(result.progressPhases).toEqual([
"PREPARING",
"TRANSFERRING",
"TRANSFERRING",
"TRANSFERRING",
"TRANSFERRING",
"VERIFYING",
"FINALIZING",
]);
});