import { mkdir, readFile, readdir, writeFile } from "node:fs/promises"; const cachePolicy = JSON.parse( await readFile("config/hosting/cache-policy.json", "utf8"), ); const securityPolicy = JSON.parse( await readFile("config/hosting/security-headers.json", "utf8"), ); const baseUrl = process.env.HOSTING_BASE_URL; /** @type {Record>} */ let responses; let mode; if (baseUrl) { mode = "live"; const assets = await readdir("dist/assets"); const hashedJavaScript = assets.find((file) => file.endsWith(".js")); if (!hashedJavaScript) throw new Error("No built hashed JavaScript found."); const paths = { index: "/", runtimeConfig: "/config.json", releaseManifest: "/release-manifest.json", hashedAsset: `/assets/${hashedJavaScript}`, }; responses = {}; for (const [surface, pathname] of Object.entries(paths)) { const response = await fetch(new URL(pathname, baseUrl)); responses[surface] = Object.fromEntries( [...response.headers.entries()].map(([name, value]) => [ name.toLowerCase(), value, ]), ); } } else { mode = "fixture"; responses = JSON.parse( await readFile("config/hosting/response-headers.fixture.json", "utf8"), ).responses; } const results = []; for (const [surface, policy] of Object.entries(cachePolicy.surfaces)) { if (!("cacheControl" in policy)) continue; const observed = responses[surface]?.["cache-control"]; results.push({ surface, header: "cache-control", expected: policy.cacheControl, observed, passed: observed === policy.cacheControl, }); const observedContentType = responses[surface]?.["content-type"]; const observedMime = observedContentType ?.split(";", 1)[0] .trim() .toLowerCase(); results.push({ surface, header: "content-type", expected: policy.contentTypes, observed: observedContentType, passed: policy.contentTypes.includes(observedMime), }); if (policy.securityHeaders) { for (const [header, expected] of Object.entries(securityPolicy.headers)) { const observedSecurity = responses[surface]?.[header.toLowerCase()]; results.push({ surface, header: header.toLowerCase(), expected, observed: observedSecurity, passed: observedSecurity === expected, }); } } } results.push({ surface: "sourceMap", header: "public", expected: false, observed: cachePolicy.surfaces.sourceMap.public, passed: cachePolicy.surfaces.sourceMap.public === false, }); results.push({ surface: "serviceWorker", header: "enabled", expected: false, observed: cachePolicy.surfaces.serviceWorker.enabled, passed: cachePolicy.surfaces.serviceWorker.enabled === false, }); const passed = results.every((result) => result.passed); await mkdir("artifacts/release", { recursive: true }); await writeFile( "artifacts/release/hosting-headers.json", `${JSON.stringify( { schemaVersion: 1, generatedAt: new Date().toISOString(), mode, baseUrl: baseUrl ?? null, providerVerificationRequired: mode !== "live", results, passed, }, null, 2, )}\n`, ); if (!passed) { process.stderr.write( "Hosting cache/content-type/security header verification failed.\n", ); process.exit(1); } process.stdout.write( `Hosting header contract: PASS (${mode}; live verification ${ mode === "live" ? "complete" : "required before promotion" })\n`, );