@xemahq/xema 0.40.3 → 0.41.1

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 (46) 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 +289 -19
  5. package/dist/edition/verify-image-evidence.bundle.provenance.json +71 -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/dispatched-runtime-components.mjs +90 -1
  24. package/edition/edition-artifact.mjs +31 -14
  25. package/edition/edition-constants.mjs +9 -0
  26. package/edition/edition-contract.json +2 -1
  27. package/edition/{develop-seal.mjs → edition-image-seal.mjs} +36 -17
  28. package/edition/edition-workspace.mjs +4 -3
  29. package/edition/evidence-trust-pin.mjs +28 -8
  30. package/edition/evidence-trust-policy.mjs +51 -7
  31. package/edition/image-evidence.mjs +2 -2
  32. package/edition/lib.mjs +20 -11
  33. package/edition/oci-image-source-evidence.mjs +3 -0
  34. package/edition/oras-process.mjs +3 -3
  35. package/edition/oras.mjs +47 -5
  36. package/edition/produce-edition-catalogue-evidence.mjs +252 -0
  37. package/edition/produce-image-source-evidence.mjs +11 -2
  38. package/edition/release-edition.mjs +54 -0
  39. package/edition/repin-evidence-trust.mjs +5 -3
  40. package/edition/resolve-images.mjs +40 -5
  41. package/edition/sigstore-bundle-media-type.mjs +4 -0
  42. package/edition/trust-policy-arming.mjs +14 -1
  43. package/edition/verify-catalogue-evidence.mjs +245 -0
  44. package/edition/verify-image-evidence.mjs +15 -1
  45. package/package.json +2 -2
  46. 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",
@@ -62918,6 +62924,14 @@ function resetEditionWorkspaceConfig() {
62918
62924
  cached = void 0;
62919
62925
  }
62920
62926
 
62927
+ // edition/string-order.mjs
62928
+ function compareStrings(a, b) {
62929
+ if (a === b) {
62930
+ return 0;
62931
+ }
62932
+ return a < b ? -1 : 1;
62933
+ }
62934
+
62921
62935
  // edition/evidence-grammars.mjs
62922
62936
  var COMMIT_PATTERN = /^[a-f0-9]{40}$/;
62923
62937
  var SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
@@ -62933,16 +62947,6 @@ var requireFromHere2 = createRequire2(import.meta.url);
62933
62947
 
62934
62948
  // edition/operation-requirements.mjs
62935
62949
  import { createRequire as createRequire3 } from "node:module";
62936
-
62937
- // edition/string-order.mjs
62938
- function compareStrings(a, b) {
62939
- if (a === b) {
62940
- return 0;
62941
- }
62942
- return a < b ? -1 : 1;
62943
- }
62944
-
62945
- // edition/operation-requirements.mjs
62946
62950
  var requireFromHere3 = createRequire3(import.meta.url);
62947
62951
  var PRINCIPAL_PRIVILEGE_FIELDS = Object.freeze(["requiresOperations", "optionalOperations", "requiresOrganizationSweeps"]);
62948
62952
 
@@ -63107,7 +63111,7 @@ function assertEngineImage(image) {
63107
63111
  return image;
63108
63112
  }
63109
63113
  var COMMIT_PATTERN2 = /^[0-9a-f]{40}$/;
63110
- var CATALOGUE_DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
63114
+ var DIGEST_PIN_PATTERN = /^sha256:[0-9a-f]{64}$/;
63111
63115
  var exactKeys = (value, keys, where) => {
63112
63116
  if (value === null || typeof value !== "object" || Array.isArray(value) || Object.keys(value).sort().join() !== [...keys].sort().join()) {
63113
63117
  throw new Error(`${where} must be exactly {${keys.join(", ")}}`);
@@ -63128,13 +63132,14 @@ function parseEditionDescriptor(value) {
63128
63132
  }
63129
63133
  const { pins, workflow } = value.provenance;
63130
63134
  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)`);
63135
+ 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
63136
  }
63133
63137
  for (const [key, pin] of Object.entries(pins)) {
63134
- const pattern = key === CATALOGUE_PIN_KEY ? CATALOGUE_DIGEST_PATTERN : COMMIT_PATTERN2;
63138
+ const digestPin = DIGEST_PIN_KEYS.includes(key);
63139
+ const pattern = digestPin ? DIGEST_PIN_PATTERN : COMMIT_PATTERN2;
63135
63140
  if (typeof pin !== "string" || !pattern.test(pin)) {
63136
63141
  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)`
63142
+ 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
63143
  );
63139
63144
  }
63140
63145
  }
@@ -64704,7 +64709,7 @@ var PIN_KEYS = Object.freeze([
64704
64709
  ]);
64705
64710
  var VERIFIER_KEYS = Object.freeze(["bundleDigest", "provenanceDigest"]);
64706
64711
  var AUTHORITY_PIN_KEYS = Object.freeze(["digest", "sourceCommit"]);
64707
- var PIN_SHAPE = "{schemaVersion, policyDigest, verifier: {bundleDigest, provenanceDigest}, kernelContractAuthority: {sourceCommit, digest}, trustedOrasBinaryDigests: [sha256:…, …]}";
64712
+ var PIN_SHAPE = "{schemaVersion, policyDigest, verifier: {bundleDigest, provenanceDigest}, kernelContractAuthority: {sourceCommit, digest} | null, trustedOrasBinaryDigests: [sha256:…, …]}";
64708
64713
  var exactKeys2 = (value, keys) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).sort().join() === keys.join();
64709
64714
  function requireDigest(value, what) {
64710
64715
  if (typeof value !== "string" || !SHA256_DIGEST.test(value)) {
@@ -64739,7 +64744,7 @@ function readEvidenceTrustPin({ dataRoot: dataRoot2, declaration }) {
64739
64744
  MAX_PIN_BYTES
64740
64745
  );
64741
64746
  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)) {
64747
+ if (!exactKeys2(pin, PIN_KEYS) || !exactKeys2(pin.verifier, VERIFIER_KEYS) || !(pin.kernelContractAuthority === null || exactKeys2(pin.kernelContractAuthority, AUTHORITY_PIN_KEYS)) || !Array.isArray(pin.trustedOrasBinaryDigests)) {
64743
64748
  throw new Error(`${declaration.pin}: the pin is exactly ${PIN_SHAPE}`);
64744
64749
  }
64745
64750
  if (pin.schemaVersion !== EVIDENCE_TRUST_PIN_SCHEMA_VERSION) {
@@ -64757,7 +64762,7 @@ function readEvidenceTrustPin({ dataRoot: dataRoot2, declaration }) {
64757
64762
  "verifier.provenanceDigest"
64758
64763
  )
64759
64764
  }),
64760
- kernelContractAuthority: Object.freeze({
64765
+ kernelContractAuthority: pin.kernelContractAuthority === null ? null : Object.freeze({
64761
64766
  sourceCommit: requireCommit(pin.kernelContractAuthority.sourceCommit),
64762
64767
  digest: requireDigest(pin.kernelContractAuthority.digest, "kernelContractAuthority.digest")
64763
64768
  }),
@@ -64802,6 +64807,12 @@ function readStatedKernelContractAuthority({ dataRoot: dataRoot2, schemas: schem
64802
64807
  }
64803
64808
  function assertPinnedKernelContractAuthority({ pin, authority, label: label2 }) {
64804
64809
  const actual = kernelContractAuthorityPin(authority);
64810
+ if (pin.kernelContractAuthority === null) {
64811
+ throw new KernelContractAuthorityPinError(
64812
+ KERNEL_CONTRACT_AUTHORITY_NOT_PINNED_ONE,
64813
+ `${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}\``
64814
+ );
64815
+ }
64805
64816
  if (actual.sourceCommit !== pin.kernelContractAuthority.sourceCommit || actual.digest !== pin.kernelContractAuthority.digest) {
64806
64817
  throw new KernelContractAuthorityPinError(
64807
64818
  KERNEL_CONTRACT_AUTHORITY_NOT_PINNED_ONE,
@@ -65169,6 +65180,259 @@ async function loadVerifierKernelSchemas() {
65169
65180
  return { schemas, editionProtocol: edition_protocol_default };
65170
65181
  }
65171
65182
 
65183
+ // edition/sigstore-bundle-media-type.mjs
65184
+ var BUNDLE_MEDIA_TYPE = "application/vnd.dev.sigstore.bundle.v0.3+json";
65185
+
65186
+ // edition/trust-policy-arming.mjs
65187
+ var TrustPolicyArmingState = Object.freeze({
65188
+ ARMED: "armed",
65189
+ UNARMED: "unarmed",
65190
+ PARTIAL: "partial"
65191
+ });
65192
+ function assertArmingChannel(schemas2, channel) {
65193
+ if (!schemas2.EVIDENCE_CHANNELS.includes(channel)) {
65194
+ throw new Error(
65195
+ `trust-policy arming is judged for one channel; got ${JSON.stringify(channel)}, expected ${schemas2.EVIDENCE_CHANNELS.join(" | ")}`
65196
+ );
65197
+ }
65198
+ }
65199
+ function assessTrustPolicyArming(policy, schemas2, channel, { consumesCatalogue = false } = {}) {
65200
+ assertArmingChannel(schemas2, channel);
65201
+ const unmet = [];
65202
+ const stages = [
65203
+ ["image-producer", schemas2.IMAGE_PRODUCER_PREDICATE_TYPE],
65204
+ ["distribution-completeness", schemas2.DISTRIBUTION_IMAGES_PREDICATE_TYPE],
65205
+ ["delivery-entitlement", schemas2.IMAGE_DELIVERY_ENTITLEMENT_PREDICATE_TYPE]
65206
+ ];
65207
+ if (consumesCatalogue) {
65208
+ if (typeof schemas2.EDITION_CATALOGUE_PREDICATE_TYPE !== "string") {
65209
+ unmet.push("this kernel states no edition-catalogue predicate (EDITION_CATALOGUE_PREDICATE_TYPE), so a catalogue consumer cannot be armed against it.");
65210
+ } else {
65211
+ stages.push(["edition-catalogue", schemas2.EDITION_CATALOGUE_PREDICATE_TYPE]);
65212
+ }
65213
+ }
65214
+ const onChannel = policy.policies.filter((candidate) => candidate.channel === channel);
65215
+ const authorized = stages.filter(([, predicateType]) => onChannel.some((candidate) => candidate.predicateTypes.includes(predicateType)));
65216
+ if (policy.policies.length === 0) {
65217
+ unmet.push(
65218
+ 'policies[] is empty — no signer identity is authorized, so verifySigstoreEvidenceDescriptor throws "offline trust policy authorizes no signer" for every predicate before reading any bundle.'
65219
+ );
65220
+ } else {
65221
+ for (const [stage, predicateType] of stages.filter((candidate) => !authorized.includes(candidate))) {
65222
+ unmet.push(
65223
+ `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.`
65224
+ );
65225
+ }
65226
+ }
65227
+ if (policy.trustedCosignBinaryDigests.length === 0) {
65228
+ unmet.push(
65229
+ "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."
65230
+ );
65231
+ }
65232
+ if (policy.trustedGitBinaryDigests.length === 0) {
65233
+ unmet.push(
65234
+ "trustedGitBinaryDigests[] is empty — the same membership test rejects every git binary, so no verified release checkout can be established."
65235
+ );
65236
+ }
65237
+ const armed = unmet.length === 0;
65238
+ const bootstrap = policy.policies.length === 0 && policy.trustedCosignBinaryDigests.length === 0 && policy.trustedGitBinaryDigests.length === 0;
65239
+ const anotherChannelOnly = onChannel.length === 0 && policy.policies.length > 0;
65240
+ const state = armed ? TrustPolicyArmingState.ARMED : bootstrap || anotherChannelOnly ? TrustPolicyArmingState.UNARMED : TrustPolicyArmingState.PARTIAL;
65241
+ return { state, armed, unmet };
65242
+ }
65243
+
65244
+ // edition/verify-catalogue-evidence.mjs
65245
+ var CATALOGUE_EVIDENCE_MODE = "catalogue-evidence";
65246
+ 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>";
65247
+ var CATALOGUE_EVIDENCE_STATEMENT_FILE = "statement.json";
65248
+ var CATALOGUE_EVIDENCE_BUNDLE_FILE = "bundle.sigstore.json";
65249
+ var CATALOGUE_EVIDENCE_UNARMED_CODE = EDITION_CONTRACT.evidenceTrust.refusal.code;
65250
+ var CatalogueEvidenceRefusalCode = Object.freeze({
65251
+ SubjectMismatch: "catalogue_evidence_subject_mismatch",
65252
+ OfferingMismatch: "catalogue_evidence_offering_mismatch",
65253
+ LockDigestMismatch: "catalogue_evidence_lock_digest_mismatch"
65254
+ });
65255
+ var SHA256_DIGEST3 = /^sha256:[a-f0-9]{64}$/;
65256
+ var COMMIT = /^[a-f0-9]{40}$/;
65257
+ var ARMING_FLAGS = Object.freeze(["--channel"]);
65258
+ var VERIFY_FLAGS = Object.freeze([
65259
+ "--channel",
65260
+ "--evidence-root",
65261
+ "--statement-digest",
65262
+ "--bundle-digest",
65263
+ "--workflow-sha",
65264
+ "--offering-id",
65265
+ "--subject-digest",
65266
+ "--catalogue-layer-digest",
65267
+ "--lock-layer-digest",
65268
+ "--cosign"
65269
+ ]);
65270
+ var ABSOLUTE_FLAGS = Object.freeze(["--evidence-root", "--cosign"]);
65271
+ var DIGEST_FLAGS = Object.freeze(["--statement-digest", "--bundle-digest", "--subject-digest", "--catalogue-layer-digest", "--lock-layer-digest"]);
65272
+ var CatalogueEvidenceUsageError = class extends Error {
65273
+ constructor(message) {
65274
+ super(message);
65275
+ this.name = "CatalogueEvidenceUsageError";
65276
+ }
65277
+ };
65278
+ var CatalogueEvidenceUnarmedError = class extends Error {
65279
+ constructor(message) {
65280
+ super(`${CATALOGUE_EVIDENCE_UNARMED_CODE}: ${message}`);
65281
+ this.name = "EvidenceTrustRequiredError";
65282
+ this.code = CATALOGUE_EVIDENCE_UNARMED_CODE;
65283
+ }
65284
+ };
65285
+ var CatalogueEvidenceRefusal = class extends Error {
65286
+ constructor(code, message) {
65287
+ super(`${code}: ${message}`);
65288
+ this.name = "CatalogueEvidenceRefusal";
65289
+ this.code = code;
65290
+ }
65291
+ };
65292
+ var hexOf = (digest) => digest.slice("sha256:".length);
65293
+ function parseFlags(args, allowed) {
65294
+ const flags = /* @__PURE__ */ new Map();
65295
+ for (let index = 0; index < args.length; index += 2) {
65296
+ const flag = args[index];
65297
+ const value = args[index + 1];
65298
+ if (typeof flag !== "string" || !allowed.includes(flag)) {
65299
+ throw new CatalogueEvidenceUsageError(`unknown or unexpected argument ${JSON.stringify(flag)}`);
65300
+ }
65301
+ if (value === void 0 || value.startsWith("--")) {
65302
+ throw new CatalogueEvidenceUsageError(`${flag} requires a value`);
65303
+ }
65304
+ if (flags.has(flag)) {
65305
+ throw new CatalogueEvidenceUsageError(`${flag} was given twice`);
65306
+ }
65307
+ flags.set(flag, value);
65308
+ }
65309
+ for (const flag of allowed) {
65310
+ if (!flags.has(flag)) {
65311
+ throw new CatalogueEvidenceUsageError(`${flag} is required`);
65312
+ }
65313
+ }
65314
+ for (const flag of ABSOLUTE_FLAGS.filter((candidate) => flags.has(candidate))) {
65315
+ if (!flags.get(flag).startsWith("/")) {
65316
+ throw new CatalogueEvidenceUsageError(`${flag} must be an absolute path`);
65317
+ }
65318
+ }
65319
+ for (const flag of DIGEST_FLAGS.filter((candidate) => flags.has(candidate))) {
65320
+ if (!SHA256_DIGEST3.test(flags.get(flag))) {
65321
+ throw new CatalogueEvidenceUsageError(`${flag} must be sha256:<64 lowercase hex>`);
65322
+ }
65323
+ }
65324
+ if (flags.has("--workflow-sha") && !COMMIT.test(flags.get("--workflow-sha"))) {
65325
+ throw new CatalogueEvidenceUsageError("--workflow-sha must be a 40-character lowercase hexadecimal git commit SHA");
65326
+ }
65327
+ return flags;
65328
+ }
65329
+ async function armedAnchors({ channel, env, bundlePath }) {
65330
+ assertSanitizedOperatorEnvironment(env);
65331
+ const running = readRunningVerifier(bundlePath);
65332
+ const { schemas: schemas2 } = await loadVerifierKernelSchemas();
65333
+ resetEditionWorkspaceConfig();
65334
+ const declaration = editionWorkspaceConfig().evidenceTrustPolicy;
65335
+ if (declaration.policy === null) {
65336
+ throw new CatalogueEvidenceUnarmedError(`${dataRoot()} declares no evidenceTrustPolicy in edition-workspace.json`);
65337
+ }
65338
+ const { policy, policyDigest } = loadDeclaredTrustPolicy({ dataRoot: dataRoot(), declaration, schemas: schemas2 });
65339
+ const pin = readEvidenceTrustPin({ dataRoot: dataRoot(), declaration });
65340
+ assertPinnedPolicy({ pin, policyDigest });
65341
+ assertPinnedVerifier({ pin, actual: verifierDigests(running) });
65342
+ const { state, unmet } = assessTrustPolicyArming(policy, schemas2, channel, { consumesCatalogue: true });
65343
+ if (state !== TrustPolicyArmingState.ARMED) {
65344
+ throw new CatalogueEvidenceUnarmedError(
65345
+ `the declared policy is ${state.toUpperCase()} on the ${channel} channel for a catalogue consumer: ${unmet.join("; ")}`
65346
+ );
65347
+ }
65348
+ return { schemas: schemas2, policy };
65349
+ }
65350
+ async function runCatalogueEvidence({ argv, env, bundlePath }) {
65351
+ const [mode, phase, ...tail] = argv;
65352
+ if (mode !== CATALOGUE_EVIDENCE_MODE || phase !== "arming" && phase !== "verify") {
65353
+ throw new CatalogueEvidenceUsageError(CATALOGUE_EVIDENCE_USAGE);
65354
+ }
65355
+ let rest;
65356
+ try {
65357
+ rest = configureEditionWorkspaceFromArgv(tail, [WorkspaceRoot.Data], { refuseOthers: true });
65358
+ } catch (error) {
65359
+ throw new CatalogueEvidenceUsageError(error.message);
65360
+ }
65361
+ const flags = parseFlags(rest, phase === "arming" ? ARMING_FLAGS : VERIFY_FLAGS);
65362
+ const channel = flags.get("--channel");
65363
+ const { schemas: schemas2, policy } = await armedAnchors({ channel, env, bundlePath });
65364
+ if (phase === "arming") {
65365
+ return `${JSON.stringify({ channel, state: TrustPolicyArmingState.ARMED })}
65366
+ `;
65367
+ }
65368
+ const offeringId = flags.get("--offering-id");
65369
+ const descriptor = {
65370
+ statementPath: CATALOGUE_EVIDENCE_STATEMENT_FILE,
65371
+ statementDigest: flags.get("--statement-digest"),
65372
+ bundlePath: CATALOGUE_EVIDENCE_BUNDLE_FILE,
65373
+ bundleDigest: flags.get("--bundle-digest"),
65374
+ bundleMediaType: BUNDLE_MEDIA_TYPE
65375
+ };
65376
+ const trustedCosign = prepareTrustedCosignBinary({ cosignBinary: flags.get("--cosign"), policy });
65377
+ let statement;
65378
+ try {
65379
+ ({ statement } = verifySigstoreEvidenceDescriptor({
65380
+ evidenceRoot: flags.get("--evidence-root"),
65381
+ descriptor,
65382
+ policy,
65383
+ predicateType: schemas2.EDITION_CATALOGUE_PREDICATE_TYPE,
65384
+ channel,
65385
+ expectedWorkflowSha: flags.get("--workflow-sha"),
65386
+ parseStatement: schemas2.parseEditionCatalogueStatement,
65387
+ policyRoot: dataRoot(),
65388
+ trustedCosign
65389
+ }));
65390
+ } finally {
65391
+ trustedCosign.dispose();
65392
+ }
65393
+ const [subject] = statement.subject;
65394
+ const expectedSubject = `xema-edition-${offeringId}`;
65395
+ if (subject.digest.sha256 !== hexOf(flags.get("--subject-digest")) || subject.name !== expectedSubject) {
65396
+ throw new CatalogueEvidenceRefusal(
65397
+ CatalogueEvidenceRefusalCode.SubjectMismatch,
65398
+ `the statement is over ${subject.name}@sha256:${subject.digest.sha256}, not ${expectedSubject}@${flags.get("--subject-digest")}`
65399
+ );
65400
+ }
65401
+ const refusal = schemas2.editionCatalogueRefusal(statement.predicate, {
65402
+ channel,
65403
+ catalogueLayerDigest: flags.get("--catalogue-layer-digest")
65404
+ });
65405
+ if (refusal !== void 0) {
65406
+ throw new CatalogueEvidenceRefusal(
65407
+ refusal,
65408
+ `the statement states channel ${statement.predicate.channel} and catalogue ${statement.predicate.catalogueDigest}; this catalogue is on ${channel} with layer ${flags.get("--catalogue-layer-digest")}`
65409
+ );
65410
+ }
65411
+ if (statement.predicate.offeringId !== offeringId) {
65412
+ throw new CatalogueEvidenceRefusal(
65413
+ CatalogueEvidenceRefusalCode.OfferingMismatch,
65414
+ `the statement is for offering ${statement.predicate.offeringId}, not ${offeringId}`
65415
+ );
65416
+ }
65417
+ if (statement.predicate.lockDigest !== hexOf(flags.get("--lock-layer-digest"))) {
65418
+ throw new CatalogueEvidenceRefusal(
65419
+ CatalogueEvidenceRefusalCode.LockDigestMismatch,
65420
+ `the statement states lock digest ${statement.predicate.lockDigest}, not that of the lock layer ${flags.get("--lock-layer-digest")}`
65421
+ );
65422
+ }
65423
+ return `${JSON.stringify({ verified: true, offeringId, channel, statementDigest: descriptor.statementDigest })}
65424
+ `;
65425
+ }
65426
+ async function runCatalogueEvidenceEntry({ argv, env, bundlePath }) {
65427
+ try {
65428
+ process.stdout.write(await runCatalogueEvidence({ argv, env, bundlePath }));
65429
+ } catch (error) {
65430
+ process.stderr.write(`catalogue-evidence: ${error.name}: ${error.message}
65431
+ `);
65432
+ process.exitCode = error instanceof CatalogueEvidenceUsageError ? 2 : 1;
65433
+ }
65434
+ }
65435
+
65172
65436
  // edition/verify-image-evidence.mjs
65173
65437
  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
65438
  var EVIDENCE_CHANNEL_OF_EDITION_CHANNEL = Object.freeze({
@@ -65512,7 +65776,13 @@ edition read from ${editionsRoot()} at editions checkout commit ${releaseSourceC
65512
65776
  trustedGit.dispose();
65513
65777
  }
65514
65778
  }
65515
- if (isEntryModule(import.meta.url)) {
65779
+ if (isEntryModule(import.meta.url) && process.argv[2] === CATALOGUE_EVIDENCE_MODE) {
65780
+ await runCatalogueEvidenceEntry({
65781
+ argv: process.argv.slice(2),
65782
+ env: process.env,
65783
+ bundlePath: process.argv[1]
65784
+ });
65785
+ } else if (isEntryModule(import.meta.url)) {
65516
65786
  await verifyEvidence({
65517
65787
  argv: process.argv.slice(2),
65518
65788
  env: process.env,