120 lines
5.1 KiB
TypeScript
120 lines
5.1 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { createApp } from "../../apps/api/src/app.js";
|
|
import {
|
|
MAX_PUBLIC_CACHE_BYTES,
|
|
buildPublicAssetUrl,
|
|
isPublicCacheDescriptor,
|
|
isPublicServiceWorkerRoute,
|
|
planPublicCacheWrite,
|
|
type PublicAssetLruEntry,
|
|
} from "../../apps/web/src/public-asset-cache.js";
|
|
|
|
const resourceIds = [
|
|
"123e4567-e89b-42d3-a456-426614174001",
|
|
"123e4567-e89b-42d3-a456-426614174002",
|
|
"123e4567-e89b-42d3-a456-426614174003",
|
|
"123e4567-e89b-42d3-a456-426614174004",
|
|
] as const;
|
|
|
|
describe("TDD-WP0-CACHE-001 public allowlist LRU", () => {
|
|
it("freezes the 150 MiB policy and allows exact equality", () => {
|
|
expect(MAX_PUBLIC_CACHE_BYTES).toBe(157_286_400);
|
|
const plan = planPublicCacheWrite([], {
|
|
bytes: MAX_PUBLIC_CACHE_BYTES,
|
|
last_accessed_at: 4,
|
|
release_version: "asset-20260727.2",
|
|
resource_id: resourceIds[0],
|
|
}, MAX_PUBLIC_CACHE_BYTES);
|
|
expect(plan).toEqual({ accepted: true, evict: [], resulting_bytes: MAX_PUBLIC_CACHE_BYTES });
|
|
expect(planPublicCacheWrite([], {
|
|
bytes: MAX_PUBLIC_CACHE_BYTES + 1,
|
|
last_accessed_at: 4,
|
|
release_version: "asset-20260727.2",
|
|
resource_id: resourceIds[0],
|
|
}, MAX_PUBLIC_CACHE_BYTES)).toEqual({ accepted: false, evict: [], resulting_bytes: 0 });
|
|
});
|
|
|
|
it("evicts old releases first and then the least recently used entry before writing", () => {
|
|
const entries: PublicAssetLruEntry[] = [
|
|
{ bytes: 40, last_accessed_at: 30, release_version: "asset-20260727.1", resource_id: resourceIds[0] },
|
|
{ bytes: 40, last_accessed_at: 10, release_version: "asset-20260727.1", resource_id: resourceIds[1] },
|
|
{ bytes: 40, last_accessed_at: 1, release_version: "asset-20260727.2", resource_id: resourceIds[2] },
|
|
];
|
|
const plan = planPublicCacheWrite(entries, {
|
|
bytes: 40,
|
|
last_accessed_at: 40,
|
|
release_version: "asset-20260727.2",
|
|
resource_id: resourceIds[3],
|
|
}, 120);
|
|
expect(plan).toEqual({ accepted: true, evict: [resourceIds[1]], resulting_bytes: 120 });
|
|
});
|
|
|
|
it.each([
|
|
{ access_class: "internal_preview_asset", cache_kind: "thumbnail" },
|
|
{ access_class: "private_user_asset", cache_kind: "thumbnail" },
|
|
{ access_class: "public_release_asset", cache_kind: "sticker_original" },
|
|
{ access_class: "public_release_asset", cache_kind: "generation" },
|
|
{ access_class: "public_release_asset", cache_kind: "export" },
|
|
{ access_class: "public_release_asset", cache_kind: "project" },
|
|
{ access_class: "public_release_asset", cache_kind: "prompt" },
|
|
{ access_class: "public_release_asset", cache_kind: "verification_code" },
|
|
{ access_class: "public_release_asset", cache_kind: "session" },
|
|
{ access_class: "public_release_asset", cache_kind: "unsaved_edit" },
|
|
{ access_class: "public_release_asset", cache_kind: "user_download" },
|
|
])("rejects non-allowlisted candidate $access_class/$cache_kind", (candidate) => {
|
|
expect(isPublicCacheDescriptor({
|
|
...candidate,
|
|
release_version: "asset-20260727.2",
|
|
resource_id: resourceIds[0],
|
|
})).toBe(false);
|
|
});
|
|
|
|
it.each(["thumbnail", "template_conversion", "font"] as const)("allows public %s only", (cacheKind) => {
|
|
expect(isPublicCacheDescriptor({
|
|
access_class: "public_release_asset",
|
|
cache_kind: cacheKind,
|
|
release_version: "asset-20260727.2",
|
|
resource_id: resourceIds[0],
|
|
})).toBe(true);
|
|
});
|
|
|
|
it("constructs and intercepts only same-origin versioned public asset routes", () => {
|
|
const url = buildPublicAssetUrl("asset-20260727.2", resourceIds[0]);
|
|
expect(url).toBe(`/api/v1/assets/public/asset-20260727.2/${resourceIds[0]}`);
|
|
expect(isPublicServiceWorkerRoute(new URL(url, "http://127.0.0.1:43121"), "http://127.0.0.1:43121")).toBe(true);
|
|
for (const path of [
|
|
`/api/v1/assets/preview/asset-20260727.2/${resourceIds[0]}`,
|
|
`/api/v1/private-assets/${resourceIds[0]}`,
|
|
`/api/v1/projects/${resourceIds[0]}`,
|
|
"/api/v1/support/check",
|
|
"file:///C:/private.png",
|
|
]) {
|
|
expect(isPublicServiceWorkerRoute(new URL(path, "http://127.0.0.1:43121"), "http://127.0.0.1:43121")).toBe(false);
|
|
}
|
|
});
|
|
|
|
it("serves existing public binaries as immutable versioned responses with a strong ETag", { timeout: 15_000 }, async () => {
|
|
const bytes = Buffer.from("public-thumbnail");
|
|
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
const app = await createApp({
|
|
browserGate: false,
|
|
publicAssets: {
|
|
read: () => ({ assetId: resourceIds[0], bytes, mimeType: "image/png", resourceVersion: "asset-20260727.2", sha256 }),
|
|
},
|
|
});
|
|
const response = await app.inject({
|
|
headers: { host: "127.0.0.1:43121" },
|
|
method: "GET",
|
|
url: `/api/v1/assets/public/asset-20260727.2/${resourceIds[0]}`,
|
|
});
|
|
expect(response.statusCode).toBe(200);
|
|
expect(response.headers["cache-control"]).toBe("public, max-age=31536000, immutable");
|
|
expect(response.headers.etag).toBe(`"sha256-${sha256}"`);
|
|
expect(response.headers["x-content-type-options"]).toBe("nosniff");
|
|
await app.close();
|
|
});
|
|
});
|