UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines • 3 kB
{"version":3,"file":"manifest-verify.mjs","names":[],"sources":["../../../src/services/deploy/manifest-verify.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\n/**\n * The ONE manifest SRI-verify implementation (ticket #422): fetch a pinned\n * version manifest's bytes, compute the sha384 SRI, and compare against the\n * pin. Both rollback verification (atomic-deploys 11) and version-manifest\n * slot resolution (atomic-deploys 04) build on this — previously two (three\n * counting the publish pin check, which is rollback verification) copies.\n */\n\nexport interface ManifestPin {\n /** versioned manifest filename, relative to the slot's production base */\n manifest: string;\n /** the manifest document's own SRI */\n integrity: string;\n}\n\nexport type VerifiedManifest = { ok: true; text: string } | { ok: false; reason: string };\n\nexport function manifestDocumentUrl(base: string, manifest: string): string {\n return `${base.replace(/\\/$/, \"\")}/${manifest.replace(/^\\//, \"\")}`;\n}\n\nexport function computeManifestSri(text: string): string {\n return `sha384-${createHash(\"sha384\").update(text).digest(\"base64\")}`;\n}\n\n/** Fetch the pinned manifest and verify its SRI — never throws; callers map\n * the failure reason to their own result shapes (a slot check, a thrown\n * resolution error, …). */\nexport async function fetchVerifiedManifest(input: {\n base: string;\n pin: ManifestPin;\n fetchImpl?: typeof fetch;\n}): Promise<VerifiedManifest> {\n const manifestUrl = manifestDocumentUrl(input.base, input.pin.manifest);\n let response: Response;\n try {\n response = await (input.fetchImpl ?? fetch)(manifestUrl);\n } catch (error) {\n return {\n ok: false,\n reason: `manifest fetch failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n if (!response.ok) {\n return { ok: false, reason: `manifest fetch failed: ${response.status}` };\n }\n const text = await response.text();\n const computed = computeManifestSri(text);\n if (computed !== input.pin.integrity) {\n return {\n ok: false,\n reason: `integrity mismatch for ${manifestUrl} (expected ${input.pin.integrity}, computed ${computed})`,\n };\n }\n return { ok: true, text };\n}\n"],"mappings":";;;AAmBA,SAAgB,oBAAoB,MAAc,UAA0B;CAC1E,OAAO,GAAG,KAAK,QAAQ,OAAO,EAAE,EAAE,GAAG,SAAS,QAAQ,OAAO,EAAE;AACjE;AAEA,SAAgB,mBAAmB,MAAsB;CACvD,OAAO,UAAU,WAAW,QAAQ,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,QAAQ;AACpE;;;;AAKA,eAAsB,sBAAsB,OAId;CAC5B,MAAM,cAAc,oBAAoB,MAAM,MAAM,MAAM,IAAI,QAAQ;CACtE,IAAI;CACJ,IAAI;EACF,WAAW,OAAO,MAAM,aAAa,MAAK,CAAE,WAAW;CACzD,SAAS,OAAO;EACd,OAAO;GACL,IAAI;GACJ,QAAQ,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACzF;CACF;CACA,IAAI,CAAC,SAAS,IACZ,OAAO;EAAE,IAAI;EAAO,QAAQ,0BAA0B,SAAS;CAAS;CAE1E,MAAM,OAAO,MAAM,SAAS,KAAK;CACjC,MAAM,WAAW,mBAAmB,IAAI;CACxC,IAAI,aAAa,MAAM,IAAI,WACzB,OAAO;EACL,IAAI;EACJ,QAAQ,0BAA0B,YAAY,aAAa,MAAM,IAAI,UAAU,aAAa,SAAS;CACvG;CAEF,OAAO;EAAE,IAAI;EAAM;CAAK;AAC1B"}