@xemahq/xema 0.40.3 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/commands/edition.d.ts.map +1 -1
  2. package/dist/commands/edition.js +1 -0
  3. package/dist/commands/edition.js.map +1 -1
  4. package/dist/edition/verify-image-evidence.bundle.mjs +281 -9
  5. package/dist/edition/verify-image-evidence.bundle.provenance.json +65 -47
  6. package/dist/runtime/edition/verb-map.d.ts +3 -1
  7. package/dist/runtime/edition/verb-map.d.ts.map +1 -1
  8. package/dist/runtime/edition/verb-map.js +4 -0
  9. package/dist/runtime/edition/verb-map.js.map +1 -1
  10. package/edition/README.md +5 -0
  11. package/edition/catalogue-evidence.mjs +225 -0
  12. package/edition/catalogue-fetch.mjs +40 -7
  13. package/edition/customer-edition-verbs.mjs +477 -0
  14. package/edition/customer-flags.mjs +2 -0
  15. package/edition/develop-coverage-readers.mjs +212 -0
  16. package/edition/develop-coverage-run.mjs +48 -0
  17. package/edition/develop-coverage-verdict.mjs +153 -0
  18. package/edition/develop-coverage.mjs +120 -0
  19. package/edition/develop-edition-resolve.mjs +18 -7
  20. package/edition/develop-edition.mjs +47 -220
  21. package/edition/develop-freeze.mjs +50 -13
  22. package/edition/develop-image-probe.mjs +7 -7
  23. package/edition/edition-artifact.mjs +31 -14
  24. package/edition/edition-constants.mjs +9 -0
  25. package/edition/edition-contract.json +2 -1
  26. package/edition/{develop-seal.mjs → edition-image-seal.mjs} +36 -17
  27. package/edition/edition-workspace.mjs +4 -3
  28. package/edition/evidence-trust-pin.mjs +28 -8
  29. package/edition/evidence-trust-policy.mjs +51 -7
  30. package/edition/image-evidence.mjs +2 -2
  31. package/edition/lib.mjs +7 -0
  32. package/edition/oci-image-source-evidence.mjs +3 -0
  33. package/edition/oras-process.mjs +3 -3
  34. package/edition/oras.mjs +47 -5
  35. package/edition/produce-edition-catalogue-evidence.mjs +252 -0
  36. package/edition/produce-image-source-evidence.mjs +11 -2
  37. package/edition/release-edition.mjs +54 -0
  38. package/edition/repin-evidence-trust.mjs +5 -3
  39. package/edition/sigstore-bundle-media-type.mjs +4 -0
  40. package/edition/trust-policy-arming.mjs +14 -1
  41. package/edition/verify-catalogue-evidence.mjs +245 -0
  42. package/edition/verify-image-evidence.mjs +15 -1
  43. package/package.json +2 -2
  44. package/edition/develop-customer-edition.mjs +0 -149
@@ -1 +1 @@
1
- {"version":3,"file":"edition.d.ts","sourceRoot":"","sources":["../../src/commands/edition.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyCzC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiBtD"}
1
+ {"version":3,"file":"edition.d.ts","sourceRoot":"","sources":["../../src/commands/edition.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2CzC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiBtD"}
@@ -8,6 +8,7 @@ const VERB_SUMMARY = {
8
8
  [verb_map_1.EditionVerb.Resolve]: 'Resolve the whole release lock set of an edition: xema edition resolve <id> [--check]; or a customer edition against the catalogue pinned in catalogue.pin.json beside the definition: xema edition resolve --definition <file> --channel <release|develop> --out <dir> [--source-image <source>=<registry>/<prefix>]...',
9
9
  [verb_map_1.EditionVerb.Seal]: 'Seal the image digests of an edition: xema edition seal <id> [--definition <file>] (a customer edition seals against the release catalogue pinned in catalogue.pin.json beside the definition)',
10
10
  [verb_map_1.EditionVerb.Develop]: 'Resolve a develop edition snapshot: xema edition develop <resolve|target|freeze-graph|freeze-sources|check-existing|check-overrides> ...; or a customer develop edition (catalogue pinned in catalogue.pin.json beside the definition): xema edition develop <resolve|target|check-existing|freeze-sources> --definition <file> ... (resolve: --pins <file> --out <dir> --registry <root> --engine-image <repo>@sha256:<digest> [--source-image <source>=<registry>/<prefix>]...; target: --pins <file> --registry <root> --engine-image <repo>@sha256:<digest> [--source-image ...]; check-existing: --pins <file> --artifact <dir> --engine-image <repo>@sha256:<digest> [--source-image ...]). The develop tag is sha256 of the CLI version, the engine image, the pins and the source-image map.',
11
+ [verb_map_1.EditionVerb.Release]: 'Resolve a customer release edition (catalogue pinned for release in catalogue.pin.json beside the definition): xema edition release <freeze-sources|target|check-existing|resolve> --definition <file> ... (freeze-sources: --out <pins.json>, each source at its declared ref; resolve: --pins <file> --out <dir> --registry <root> --engine-image <repo>@sha256:<digest> [--source-image <source>=<registry>/<prefix>]...; target: --pins <file> --registry <root> --engine-image <repo>@sha256:<digest> [--source-image ...]; resolve and check-existing are refused until the release catalogue evidence is verified)',
11
12
  [verb_map_1.EditionVerb.Artifact]: 'Write the OCI artifact files of a release edition from the committed sealed locks: xema edition artifact <id> --channel release --registry <root> --coordinate <tag> --engine-image <repo>@sha256:<digest> --out <dir>',
12
13
  [verb_map_1.EditionVerb.Catalogue]: 'Write the catalogue.json of a release offering from its committed sealed locks: xema edition catalogue <id> --out <dir>',
13
14
  [verb_map_1.EditionVerb.Index]: `Rebuild a catalogue index: xema edition index <${Object.values(verb_map_1.EditionIndexKind).join('|')}> [--check]; xema edition index runtime-image-source --repin-contract-authority --kernel-commit <40-hex> replaces only the contract authority of the committed index with the kernel checkout's at the stated commit (its HEAD must equal it)`,
@@ -1 +1 @@
1
- {"version":3,"file":"edition.js","sourceRoot":"","sources":["../../src/commands/edition.ts"],"names":[],"mappings":";;AA6CA,0CAiBC;AA9DD,kDAA8D;AAC9D,4DAA8D;AAC9D,0DAA2H;AAW3H,MAAM,YAAY,GAA0C;IAC1D,CAAC,sBAAW,CAAC,OAAO,CAAC,EACnB,0TAA0T;IAC5T,CAAC,sBAAW,CAAC,IAAI,CAAC,EAAE,gMAAgM;IACpN,CAAC,sBAAW,CAAC,OAAO,CAAC,EAAE,swBAAswB;IAC7xB,CAAC,sBAAW,CAAC,QAAQ,CAAC,EACpB,wNAAwN;IAC1N,CAAC,sBAAW,CAAC,SAAS,CAAC,EAAE,yHAAyH;IAClJ,CAAC,sBAAW,CAAC,KAAK,CAAC,EAAE,kDAAkD,MAAM,CAAC,MAAM,CAAC,2BAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,+OAA+O;IAC/V,CAAC,sBAAW,CAAC,KAAK,CAAC,EAAE,oIAAoI;IACzJ,CAAC,sBAAW,CAAC,GAAG,CAAC,EAAE,qEAAqE;IACxF,CAAC,sBAAW,CAAC,eAAe,CAAC,EAAE,qGAAqG;IACpI,CAAC,sBAAW,CAAC,eAAe,CAAC,EAAE,wEAAwE;IACvG,CAAC,sBAAW,CAAC,kBAAkB,CAAC,EAAE,mIAAmI;IACrK,CAAC,sBAAW,CAAC,cAAc,CAAC,EAC1B,yQAAyQ;IAC3Q,CAAC,sBAAW,CAAC,QAAQ,CAAC,EAAE,+EAA+E,MAAM,CAAC,MAAM,CAAC,8BAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;IACxJ,CAAC,sBAAW,CAAC,IAAI,CAAC,EAAE,6FAA6F;IACjH,CAAC,sBAAW,CAAC,KAAK,CAAC,EAAE,6JAA6J;IAClL,CAAC,sBAAW,CAAC,QAAQ,CAAC,EAAE,gGAAgG,MAAM,CAAC,MAAM,CAAC,mCAAwB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,qKAAqK;IAC9U,CAAC,sBAAW,CAAC,cAAc,CAAC,EAC1B,6LAA6L;IAC/L,CAAC,sBAAW,CAAC,MAAM,CAAC,EAClB,yMAAyM;IAC3M,CAAC,sBAAW,CAAC,GAAG,CAAC,EACf,mWAAmW;IACrW,CAAC,sBAAW,CAAC,KAAK,CAAC,EACjB,qMAAqM;IACvM,CAAC,sBAAW,CAAC,aAAa,CAAC,EACzB,uMAAuM;CAC1M,CAAC;AAEF,SAAgB,eAAe,CAAC,OAAgB;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACvF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,sBAAW,CAAC,EAAE,CAAC;QAC9C,OAAO;aACJ,OAAO,CAAC,IAAI,CAAC;aACb,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;aAC/B,QAAQ,CAAC,WAAW,EAAE,0DAA0D,CAAC;aACjF,kBAAkB,EAAE;aACpB,MAAM,CAAC,CAAC,IAAc,EAAE,EAAE;YACzB,IAAI,CAAC;gBACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,0BAAc,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAA,qBAAQ,EAAC,4BAAe,CAAC,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACjG,CAAC;QACH,CAAC,CAAC,CAAC;IACP,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"edition.js","sourceRoot":"","sources":["../../src/commands/edition.ts"],"names":[],"mappings":";;AA+CA,0CAiBC;AAhED,kDAA8D;AAC9D,4DAA8D;AAC9D,0DAA2H;AAW3H,MAAM,YAAY,GAA0C;IAC1D,CAAC,sBAAW,CAAC,OAAO,CAAC,EACnB,0TAA0T;IAC5T,CAAC,sBAAW,CAAC,IAAI,CAAC,EAAE,gMAAgM;IACpN,CAAC,sBAAW,CAAC,OAAO,CAAC,EAAE,swBAAswB;IAC7xB,CAAC,sBAAW,CAAC,OAAO,CAAC,EACnB,2lBAA2lB;IAC7lB,CAAC,sBAAW,CAAC,QAAQ,CAAC,EACpB,wNAAwN;IAC1N,CAAC,sBAAW,CAAC,SAAS,CAAC,EAAE,yHAAyH;IAClJ,CAAC,sBAAW,CAAC,KAAK,CAAC,EAAE,kDAAkD,MAAM,CAAC,MAAM,CAAC,2BAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,+OAA+O;IAC/V,CAAC,sBAAW,CAAC,KAAK,CAAC,EAAE,oIAAoI;IACzJ,CAAC,sBAAW,CAAC,GAAG,CAAC,EAAE,qEAAqE;IACxF,CAAC,sBAAW,CAAC,eAAe,CAAC,EAAE,qGAAqG;IACpI,CAAC,sBAAW,CAAC,eAAe,CAAC,EAAE,wEAAwE;IACvG,CAAC,sBAAW,CAAC,kBAAkB,CAAC,EAAE,mIAAmI;IACrK,CAAC,sBAAW,CAAC,cAAc,CAAC,EAC1B,yQAAyQ;IAC3Q,CAAC,sBAAW,CAAC,QAAQ,CAAC,EAAE,+EAA+E,MAAM,CAAC,MAAM,CAAC,8BAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;IACxJ,CAAC,sBAAW,CAAC,IAAI,CAAC,EAAE,6FAA6F;IACjH,CAAC,sBAAW,CAAC,KAAK,CAAC,EAAE,6JAA6J;IAClL,CAAC,sBAAW,CAAC,QAAQ,CAAC,EAAE,gGAAgG,MAAM,CAAC,MAAM,CAAC,mCAAwB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,qKAAqK;IAC9U,CAAC,sBAAW,CAAC,cAAc,CAAC,EAC1B,6LAA6L;IAC/L,CAAC,sBAAW,CAAC,MAAM,CAAC,EAClB,yMAAyM;IAC3M,CAAC,sBAAW,CAAC,GAAG,CAAC,EACf,mWAAmW;IACrW,CAAC,sBAAW,CAAC,KAAK,CAAC,EACjB,qMAAqM;IACvM,CAAC,sBAAW,CAAC,aAAa,CAAC,EACzB,uMAAuM;CAC1M,CAAC;AAEF,SAAgB,eAAe,CAAC,OAAgB;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACvF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,sBAAW,CAAC,EAAE,CAAC;QAC9C,OAAO;aACJ,OAAO,CAAC,IAAI,CAAC;aACb,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;aAC/B,QAAQ,CAAC,WAAW,EAAE,0DAA0D,CAAC;aACjF,kBAAkB,EAAE;aACpB,MAAM,CAAC,CAAC,IAAc,EAAE,EAAE;YACzB,IAAI,CAAC;gBACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,0BAAc,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAA,qBAAQ,EAAC,4BAAe,CAAC,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACjG,CAAC;QACH,CAAC,CAAC,CAAC;IACP,CAAC;AACH,CAAC"}
@@ -62184,7 +62184,8 @@ var edition_contract_default = {
62184
62184
  catalogue: "catalogue.json"
62185
62185
  },
62186
62186
  provenancePins: {
62187
- catalogue: "the sha256 digest (sha256:<64 hex>) of the offering artifact a customer edition was resolved against; every other pin is a 40-hex commit"
62187
+ catalogue: "the sha256 digest (sha256:<64 hex>) of the offering artifact a customer edition was resolved against",
62188
+ definition: "the sha256 digest (sha256:<64 hex>) of the canonical JSON of the customer definition a customer edition was resolved from (vendor selection, image registry mirror, Store publisher anchors, sources); every other pin is a 40-hex commit"
62188
62189
  },
62189
62190
  imageNamespaceSegment: "dev",
62190
62191
  evidenceTrust: {
@@ -62215,6 +62216,11 @@ var CATALOGUE_PIN_KEY = "catalogue";
62215
62216
  if (!(CATALOGUE_PIN_KEY in EDITION_CONTRACT.provenancePins)) {
62216
62217
  throw new Error("edition-contract.json provenancePins does not declare the catalogue pin");
62217
62218
  }
62219
+ var DEFINITION_PIN_KEY = "definition";
62220
+ if (!(DEFINITION_PIN_KEY in EDITION_CONTRACT.provenancePins)) {
62221
+ throw new Error("edition-contract.json provenancePins does not declare the definition pin");
62222
+ }
62223
+ var DIGEST_PIN_KEYS = Object.freeze([CATALOGUE_PIN_KEY, DEFINITION_PIN_KEY]);
62218
62224
  var EditionLockFile = Object.freeze({
62219
62225
  Distribution: "distribution.lock.json",
62220
62226
  Images: "images.lock.json",
@@ -63107,7 +63113,7 @@ function assertEngineImage(image) {
63107
63113
  return image;
63108
63114
  }
63109
63115
  var COMMIT_PATTERN2 = /^[0-9a-f]{40}$/;
63110
- var CATALOGUE_DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
63116
+ var DIGEST_PIN_PATTERN = /^sha256:[0-9a-f]{64}$/;
63111
63117
  var exactKeys = (value, keys, where) => {
63112
63118
  if (value === null || typeof value !== "object" || Array.isArray(value) || Object.keys(value).sort().join() !== [...keys].sort().join()) {
63113
63119
  throw new Error(`${where} must be exactly {${keys.join(", ")}}`);
@@ -63128,13 +63134,14 @@ function parseEditionDescriptor(value) {
63128
63134
  }
63129
63135
  const { pins, workflow } = value.provenance;
63130
63136
  if (pins === null || typeof pins !== "object" || Array.isArray(pins)) {
63131
- throw new Error(`${EDITION_DESCRIPTOR_FILE}: provenance.pins must map pin keys to 40-hex commits (the "${CATALOGUE_PIN_KEY}" pin to a sha256 digest)`);
63137
+ throw new Error(`${EDITION_DESCRIPTOR_FILE}: provenance.pins must map pin keys to 40-hex commits (the ${DIGEST_PIN_KEYS.map((key) => `"${key}"`).join(" and ")} pins to sha256 digests)`);
63132
63138
  }
63133
63139
  for (const [key, pin] of Object.entries(pins)) {
63134
- const pattern = key === CATALOGUE_PIN_KEY ? CATALOGUE_DIGEST_PATTERN : COMMIT_PATTERN2;
63140
+ const digestPin = DIGEST_PIN_KEYS.includes(key);
63141
+ const pattern = digestPin ? DIGEST_PIN_PATTERN : COMMIT_PATTERN2;
63135
63142
  if (typeof pin !== "string" || !pattern.test(pin)) {
63136
63143
  throw new Error(
63137
- key === CATALOGUE_PIN_KEY ? `${EDITION_DESCRIPTOR_FILE}: provenance.pins["${key}"] must be a sha256:<64 hex> digest` : `${EDITION_DESCRIPTOR_FILE}: provenance.pins must map pin keys to 40-hex commits (${JSON.stringify(key)} is not)`
63144
+ digestPin ? `${EDITION_DESCRIPTOR_FILE}: provenance.pins["${key}"] must be a sha256:<64 hex> digest` : `${EDITION_DESCRIPTOR_FILE}: provenance.pins must map pin keys to 40-hex commits (${JSON.stringify(key)} is not)`
63138
63145
  );
63139
63146
  }
63140
63147
  }
@@ -64704,7 +64711,7 @@ var PIN_KEYS = Object.freeze([
64704
64711
  ]);
64705
64712
  var VERIFIER_KEYS = Object.freeze(["bundleDigest", "provenanceDigest"]);
64706
64713
  var AUTHORITY_PIN_KEYS = Object.freeze(["digest", "sourceCommit"]);
64707
- var PIN_SHAPE = "{schemaVersion, policyDigest, verifier: {bundleDigest, provenanceDigest}, kernelContractAuthority: {sourceCommit, digest}, trustedOrasBinaryDigests: [sha256:…, …]}";
64714
+ var PIN_SHAPE = "{schemaVersion, policyDigest, verifier: {bundleDigest, provenanceDigest}, kernelContractAuthority: {sourceCommit, digest} | null, trustedOrasBinaryDigests: [sha256:…, …]}";
64708
64715
  var exactKeys2 = (value, keys) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).sort().join() === keys.join();
64709
64716
  function requireDigest(value, what) {
64710
64717
  if (typeof value !== "string" || !SHA256_DIGEST.test(value)) {
@@ -64739,7 +64746,7 @@ function readEvidenceTrustPin({ dataRoot: dataRoot2, declaration }) {
64739
64746
  MAX_PIN_BYTES
64740
64747
  );
64741
64748
  const pin = parseStrictJson(bytes.toString("utf8"), declaration.pin);
64742
- if (!exactKeys2(pin, PIN_KEYS) || !exactKeys2(pin.verifier, VERIFIER_KEYS) || !exactKeys2(pin.kernelContractAuthority, AUTHORITY_PIN_KEYS) || !Array.isArray(pin.trustedOrasBinaryDigests)) {
64749
+ if (!exactKeys2(pin, PIN_KEYS) || !exactKeys2(pin.verifier, VERIFIER_KEYS) || !(pin.kernelContractAuthority === null || exactKeys2(pin.kernelContractAuthority, AUTHORITY_PIN_KEYS)) || !Array.isArray(pin.trustedOrasBinaryDigests)) {
64743
64750
  throw new Error(`${declaration.pin}: the pin is exactly ${PIN_SHAPE}`);
64744
64751
  }
64745
64752
  if (pin.schemaVersion !== EVIDENCE_TRUST_PIN_SCHEMA_VERSION) {
@@ -64757,7 +64764,7 @@ function readEvidenceTrustPin({ dataRoot: dataRoot2, declaration }) {
64757
64764
  "verifier.provenanceDigest"
64758
64765
  )
64759
64766
  }),
64760
- kernelContractAuthority: Object.freeze({
64767
+ kernelContractAuthority: pin.kernelContractAuthority === null ? null : Object.freeze({
64761
64768
  sourceCommit: requireCommit(pin.kernelContractAuthority.sourceCommit),
64762
64769
  digest: requireDigest(pin.kernelContractAuthority.digest, "kernelContractAuthority.digest")
64763
64770
  }),
@@ -64802,6 +64809,12 @@ function readStatedKernelContractAuthority({ dataRoot: dataRoot2, schemas: schem
64802
64809
  }
64803
64810
  function assertPinnedKernelContractAuthority({ pin, authority, label: label2 }) {
64804
64811
  const actual = kernelContractAuthorityPin(authority);
64812
+ if (pin.kernelContractAuthority === null) {
64813
+ throw new KernelContractAuthorityPinError(
64814
+ KERNEL_CONTRACT_AUTHORITY_NOT_PINNED_ONE,
64815
+ `${label2} states kernel contract authority ${actual.sourceCommit} (${actual.digest}) but the pin records none (it was written for a data root without a runtime image source index); review the index, then re-pin with \`${REPIN_COMMAND}\``
64816
+ );
64817
+ }
64805
64818
  if (actual.sourceCommit !== pin.kernelContractAuthority.sourceCommit || actual.digest !== pin.kernelContractAuthority.digest) {
64806
64819
  throw new KernelContractAuthorityPinError(
64807
64820
  KERNEL_CONTRACT_AUTHORITY_NOT_PINNED_ONE,
@@ -65169,6 +65182,259 @@ async function loadVerifierKernelSchemas() {
65169
65182
  return { schemas, editionProtocol: edition_protocol_default };
65170
65183
  }
65171
65184
 
65185
+ // edition/sigstore-bundle-media-type.mjs
65186
+ var BUNDLE_MEDIA_TYPE = "application/vnd.dev.sigstore.bundle.v0.3+json";
65187
+
65188
+ // edition/trust-policy-arming.mjs
65189
+ var TrustPolicyArmingState = Object.freeze({
65190
+ ARMED: "armed",
65191
+ UNARMED: "unarmed",
65192
+ PARTIAL: "partial"
65193
+ });
65194
+ function assertArmingChannel(schemas2, channel) {
65195
+ if (!schemas2.EVIDENCE_CHANNELS.includes(channel)) {
65196
+ throw new Error(
65197
+ `trust-policy arming is judged for one channel; got ${JSON.stringify(channel)}, expected ${schemas2.EVIDENCE_CHANNELS.join(" | ")}`
65198
+ );
65199
+ }
65200
+ }
65201
+ function assessTrustPolicyArming(policy, schemas2, channel, { consumesCatalogue = false } = {}) {
65202
+ assertArmingChannel(schemas2, channel);
65203
+ const unmet = [];
65204
+ const stages = [
65205
+ ["image-producer", schemas2.IMAGE_PRODUCER_PREDICATE_TYPE],
65206
+ ["distribution-completeness", schemas2.DISTRIBUTION_IMAGES_PREDICATE_TYPE],
65207
+ ["delivery-entitlement", schemas2.IMAGE_DELIVERY_ENTITLEMENT_PREDICATE_TYPE]
65208
+ ];
65209
+ if (consumesCatalogue) {
65210
+ if (typeof schemas2.EDITION_CATALOGUE_PREDICATE_TYPE !== "string") {
65211
+ unmet.push("this kernel states no edition-catalogue predicate (EDITION_CATALOGUE_PREDICATE_TYPE), so a catalogue consumer cannot be armed against it.");
65212
+ } else {
65213
+ stages.push(["edition-catalogue", schemas2.EDITION_CATALOGUE_PREDICATE_TYPE]);
65214
+ }
65215
+ }
65216
+ const onChannel = policy.policies.filter((candidate) => candidate.channel === channel);
65217
+ const authorized = stages.filter(([, predicateType]) => onChannel.some((candidate) => candidate.predicateTypes.includes(predicateType)));
65218
+ if (policy.policies.length === 0) {
65219
+ unmet.push(
65220
+ 'policies[] is empty — no signer identity is authorized, so verifySigstoreEvidenceDescriptor throws "offline trust policy authorizes no signer" for every predicate before reading any bundle.'
65221
+ );
65222
+ } else {
65223
+ for (const [stage, predicateType] of stages.filter((candidate) => !authorized.includes(candidate))) {
65224
+ unmet.push(
65225
+ `no policy authorizes the ${stage} predicate ${predicateType} on channel "${channel}" — that stage of a ${channel} delivery would still throw "authorizes no signer" while the policy reads as armed.`
65226
+ );
65227
+ }
65228
+ }
65229
+ if (policy.trustedCosignBinaryDigests.length === 0) {
65230
+ unmet.push(
65231
+ "trustedCosignBinaryDigests[] is empty — prepareDigestPinnedExecutable tests membership with [].includes(digest), which is false for every cosign binary, so no evidence can be verified on any host."
65232
+ );
65233
+ }
65234
+ if (policy.trustedGitBinaryDigests.length === 0) {
65235
+ unmet.push(
65236
+ "trustedGitBinaryDigests[] is empty — the same membership test rejects every git binary, so no verified release checkout can be established."
65237
+ );
65238
+ }
65239
+ const armed = unmet.length === 0;
65240
+ const bootstrap = policy.policies.length === 0 && policy.trustedCosignBinaryDigests.length === 0 && policy.trustedGitBinaryDigests.length === 0;
65241
+ const anotherChannelOnly = onChannel.length === 0 && policy.policies.length > 0;
65242
+ const state = armed ? TrustPolicyArmingState.ARMED : bootstrap || anotherChannelOnly ? TrustPolicyArmingState.UNARMED : TrustPolicyArmingState.PARTIAL;
65243
+ return { state, armed, unmet };
65244
+ }
65245
+
65246
+ // edition/verify-catalogue-evidence.mjs
65247
+ var CATALOGUE_EVIDENCE_MODE = "catalogue-evidence";
65248
+ var CATALOGUE_EVIDENCE_USAGE = "usage: catalogue-evidence arming --channel <release|develop> --data-root <dir> | catalogue-evidence verify --channel <c> --data-root <dir> --evidence-root <abs dir> --statement-digest <sha256:..> --bundle-digest <sha256:..> --workflow-sha <40-hex> --offering-id <id> --subject-digest <sha256:..> --catalogue-layer-digest <sha256:..> --lock-layer-digest <sha256:..> --cosign <abs path>";
65249
+ var CATALOGUE_EVIDENCE_STATEMENT_FILE = "statement.json";
65250
+ var CATALOGUE_EVIDENCE_BUNDLE_FILE = "bundle.sigstore.json";
65251
+ var CATALOGUE_EVIDENCE_UNARMED_CODE = EDITION_CONTRACT.evidenceTrust.refusal.code;
65252
+ var CatalogueEvidenceRefusalCode = Object.freeze({
65253
+ SubjectMismatch: "catalogue_evidence_subject_mismatch",
65254
+ OfferingMismatch: "catalogue_evidence_offering_mismatch",
65255
+ LockDigestMismatch: "catalogue_evidence_lock_digest_mismatch"
65256
+ });
65257
+ var SHA256_DIGEST3 = /^sha256:[a-f0-9]{64}$/;
65258
+ var COMMIT = /^[a-f0-9]{40}$/;
65259
+ var ARMING_FLAGS = Object.freeze(["--channel"]);
65260
+ var VERIFY_FLAGS = Object.freeze([
65261
+ "--channel",
65262
+ "--evidence-root",
65263
+ "--statement-digest",
65264
+ "--bundle-digest",
65265
+ "--workflow-sha",
65266
+ "--offering-id",
65267
+ "--subject-digest",
65268
+ "--catalogue-layer-digest",
65269
+ "--lock-layer-digest",
65270
+ "--cosign"
65271
+ ]);
65272
+ var ABSOLUTE_FLAGS = Object.freeze(["--evidence-root", "--cosign"]);
65273
+ var DIGEST_FLAGS = Object.freeze(["--statement-digest", "--bundle-digest", "--subject-digest", "--catalogue-layer-digest", "--lock-layer-digest"]);
65274
+ var CatalogueEvidenceUsageError = class extends Error {
65275
+ constructor(message) {
65276
+ super(message);
65277
+ this.name = "CatalogueEvidenceUsageError";
65278
+ }
65279
+ };
65280
+ var CatalogueEvidenceUnarmedError = class extends Error {
65281
+ constructor(message) {
65282
+ super(`${CATALOGUE_EVIDENCE_UNARMED_CODE}: ${message}`);
65283
+ this.name = "EvidenceTrustRequiredError";
65284
+ this.code = CATALOGUE_EVIDENCE_UNARMED_CODE;
65285
+ }
65286
+ };
65287
+ var CatalogueEvidenceRefusal = class extends Error {
65288
+ constructor(code, message) {
65289
+ super(`${code}: ${message}`);
65290
+ this.name = "CatalogueEvidenceRefusal";
65291
+ this.code = code;
65292
+ }
65293
+ };
65294
+ var hexOf = (digest) => digest.slice("sha256:".length);
65295
+ function parseFlags(args, allowed) {
65296
+ const flags = /* @__PURE__ */ new Map();
65297
+ for (let index = 0; index < args.length; index += 2) {
65298
+ const flag = args[index];
65299
+ const value = args[index + 1];
65300
+ if (typeof flag !== "string" || !allowed.includes(flag)) {
65301
+ throw new CatalogueEvidenceUsageError(`unknown or unexpected argument ${JSON.stringify(flag)}`);
65302
+ }
65303
+ if (value === void 0 || value.startsWith("--")) {
65304
+ throw new CatalogueEvidenceUsageError(`${flag} requires a value`);
65305
+ }
65306
+ if (flags.has(flag)) {
65307
+ throw new CatalogueEvidenceUsageError(`${flag} was given twice`);
65308
+ }
65309
+ flags.set(flag, value);
65310
+ }
65311
+ for (const flag of allowed) {
65312
+ if (!flags.has(flag)) {
65313
+ throw new CatalogueEvidenceUsageError(`${flag} is required`);
65314
+ }
65315
+ }
65316
+ for (const flag of ABSOLUTE_FLAGS.filter((candidate) => flags.has(candidate))) {
65317
+ if (!flags.get(flag).startsWith("/")) {
65318
+ throw new CatalogueEvidenceUsageError(`${flag} must be an absolute path`);
65319
+ }
65320
+ }
65321
+ for (const flag of DIGEST_FLAGS.filter((candidate) => flags.has(candidate))) {
65322
+ if (!SHA256_DIGEST3.test(flags.get(flag))) {
65323
+ throw new CatalogueEvidenceUsageError(`${flag} must be sha256:<64 lowercase hex>`);
65324
+ }
65325
+ }
65326
+ if (flags.has("--workflow-sha") && !COMMIT.test(flags.get("--workflow-sha"))) {
65327
+ throw new CatalogueEvidenceUsageError("--workflow-sha must be a 40-character lowercase hexadecimal git commit SHA");
65328
+ }
65329
+ return flags;
65330
+ }
65331
+ async function armedAnchors({ channel, env, bundlePath }) {
65332
+ assertSanitizedOperatorEnvironment(env);
65333
+ const running = readRunningVerifier(bundlePath);
65334
+ const { schemas: schemas2 } = await loadVerifierKernelSchemas();
65335
+ resetEditionWorkspaceConfig();
65336
+ const declaration = editionWorkspaceConfig().evidenceTrustPolicy;
65337
+ if (declaration.policy === null) {
65338
+ throw new CatalogueEvidenceUnarmedError(`${dataRoot()} declares no evidenceTrustPolicy in edition-workspace.json`);
65339
+ }
65340
+ const { policy, policyDigest } = loadDeclaredTrustPolicy({ dataRoot: dataRoot(), declaration, schemas: schemas2 });
65341
+ const pin = readEvidenceTrustPin({ dataRoot: dataRoot(), declaration });
65342
+ assertPinnedPolicy({ pin, policyDigest });
65343
+ assertPinnedVerifier({ pin, actual: verifierDigests(running) });
65344
+ const { state, unmet } = assessTrustPolicyArming(policy, schemas2, channel, { consumesCatalogue: true });
65345
+ if (state !== TrustPolicyArmingState.ARMED) {
65346
+ throw new CatalogueEvidenceUnarmedError(
65347
+ `the declared policy is ${state.toUpperCase()} on the ${channel} channel for a catalogue consumer: ${unmet.join("; ")}`
65348
+ );
65349
+ }
65350
+ return { schemas: schemas2, policy };
65351
+ }
65352
+ async function runCatalogueEvidence({ argv, env, bundlePath }) {
65353
+ const [mode, phase, ...tail] = argv;
65354
+ if (mode !== CATALOGUE_EVIDENCE_MODE || phase !== "arming" && phase !== "verify") {
65355
+ throw new CatalogueEvidenceUsageError(CATALOGUE_EVIDENCE_USAGE);
65356
+ }
65357
+ let rest;
65358
+ try {
65359
+ rest = configureEditionWorkspaceFromArgv(tail, [WorkspaceRoot.Data], { refuseOthers: true });
65360
+ } catch (error) {
65361
+ throw new CatalogueEvidenceUsageError(error.message);
65362
+ }
65363
+ const flags = parseFlags(rest, phase === "arming" ? ARMING_FLAGS : VERIFY_FLAGS);
65364
+ const channel = flags.get("--channel");
65365
+ const { schemas: schemas2, policy } = await armedAnchors({ channel, env, bundlePath });
65366
+ if (phase === "arming") {
65367
+ return `${JSON.stringify({ channel, state: TrustPolicyArmingState.ARMED })}
65368
+ `;
65369
+ }
65370
+ const offeringId = flags.get("--offering-id");
65371
+ const descriptor = {
65372
+ statementPath: CATALOGUE_EVIDENCE_STATEMENT_FILE,
65373
+ statementDigest: flags.get("--statement-digest"),
65374
+ bundlePath: CATALOGUE_EVIDENCE_BUNDLE_FILE,
65375
+ bundleDigest: flags.get("--bundle-digest"),
65376
+ bundleMediaType: BUNDLE_MEDIA_TYPE
65377
+ };
65378
+ const trustedCosign = prepareTrustedCosignBinary({ cosignBinary: flags.get("--cosign"), policy });
65379
+ let statement;
65380
+ try {
65381
+ ({ statement } = verifySigstoreEvidenceDescriptor({
65382
+ evidenceRoot: flags.get("--evidence-root"),
65383
+ descriptor,
65384
+ policy,
65385
+ predicateType: schemas2.EDITION_CATALOGUE_PREDICATE_TYPE,
65386
+ channel,
65387
+ expectedWorkflowSha: flags.get("--workflow-sha"),
65388
+ parseStatement: schemas2.parseEditionCatalogueStatement,
65389
+ policyRoot: dataRoot(),
65390
+ trustedCosign
65391
+ }));
65392
+ } finally {
65393
+ trustedCosign.dispose();
65394
+ }
65395
+ const [subject] = statement.subject;
65396
+ const expectedSubject = `xema-edition-${offeringId}`;
65397
+ if (subject.digest.sha256 !== hexOf(flags.get("--subject-digest")) || subject.name !== expectedSubject) {
65398
+ throw new CatalogueEvidenceRefusal(
65399
+ CatalogueEvidenceRefusalCode.SubjectMismatch,
65400
+ `the statement is over ${subject.name}@sha256:${subject.digest.sha256}, not ${expectedSubject}@${flags.get("--subject-digest")}`
65401
+ );
65402
+ }
65403
+ const refusal = schemas2.editionCatalogueRefusal(statement.predicate, {
65404
+ channel,
65405
+ catalogueLayerDigest: flags.get("--catalogue-layer-digest")
65406
+ });
65407
+ if (refusal !== void 0) {
65408
+ throw new CatalogueEvidenceRefusal(
65409
+ refusal,
65410
+ `the statement states channel ${statement.predicate.channel} and catalogue ${statement.predicate.catalogueDigest}; this catalogue is on ${channel} with layer ${flags.get("--catalogue-layer-digest")}`
65411
+ );
65412
+ }
65413
+ if (statement.predicate.offeringId !== offeringId) {
65414
+ throw new CatalogueEvidenceRefusal(
65415
+ CatalogueEvidenceRefusalCode.OfferingMismatch,
65416
+ `the statement is for offering ${statement.predicate.offeringId}, not ${offeringId}`
65417
+ );
65418
+ }
65419
+ if (statement.predicate.lockDigest !== hexOf(flags.get("--lock-layer-digest"))) {
65420
+ throw new CatalogueEvidenceRefusal(
65421
+ CatalogueEvidenceRefusalCode.LockDigestMismatch,
65422
+ `the statement states lock digest ${statement.predicate.lockDigest}, not that of the lock layer ${flags.get("--lock-layer-digest")}`
65423
+ );
65424
+ }
65425
+ return `${JSON.stringify({ verified: true, offeringId, channel, statementDigest: descriptor.statementDigest })}
65426
+ `;
65427
+ }
65428
+ async function runCatalogueEvidenceEntry({ argv, env, bundlePath }) {
65429
+ try {
65430
+ process.stdout.write(await runCatalogueEvidence({ argv, env, bundlePath }));
65431
+ } catch (error) {
65432
+ process.stderr.write(`catalogue-evidence: ${error.name}: ${error.message}
65433
+ `);
65434
+ process.exitCode = error instanceof CatalogueEvidenceUsageError ? 2 : 1;
65435
+ }
65436
+ }
65437
+
65172
65438
  // edition/verify-image-evidence.mjs
65173
65439
  var USAGE = "usage: verify-image-evidence <distributionId> --evidence-root <dir> --descriptor <absolute-path> --state <absolute-path> --cosign <absolute-path> --git <absolute-path> [--evidence-set <relative-path>] [--json] [--entitlement <relative-path> --entitlement-workflow-sha <40-hex git sha> --customer <id> --mode <mode> [--target-registry <registry>]] --data-root <dir> --editions-root <dir> --kernel <dir>";
65174
65440
  var EVIDENCE_CHANNEL_OF_EDITION_CHANNEL = Object.freeze({
@@ -65512,7 +65778,13 @@ edition read from ${editionsRoot()} at editions checkout commit ${releaseSourceC
65512
65778
  trustedGit.dispose();
65513
65779
  }
65514
65780
  }
65515
- if (isEntryModule(import.meta.url)) {
65781
+ if (isEntryModule(import.meta.url) && process.argv[2] === CATALOGUE_EVIDENCE_MODE) {
65782
+ await runCatalogueEvidenceEntry({
65783
+ argv: process.argv.slice(2),
65784
+ env: process.env,
65785
+ bundlePath: process.argv[1]
65786
+ });
65787
+ } else if (isEntryModule(import.meta.url)) {
65516
65788
  await verifyEvidence({
65517
65789
  argv: process.argv.slice(2),
65518
65790
  env: process.env,