{"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"}