@xemahq/xema 0.28.0 → 0.29.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 (54) hide show
  1. package/dist/commands/edition.d.ts.map +1 -1
  2. package/dist/commands/edition.js +8 -7
  3. package/dist/commands/edition.js.map +1 -1
  4. package/dist/edition/verify-image-evidence.bundle.mjs +88 -11
  5. package/dist/edition/verify-image-evidence.bundle.provenance.json +48 -42
  6. package/dist/runtime/edition/verb-map.d.ts +2 -1
  7. package/dist/runtime/edition/verb-map.d.ts.map +1 -1
  8. package/dist/runtime/edition/verb-map.js +2 -0
  9. package/dist/runtime/edition/verb-map.js.map +1 -1
  10. package/dist/runtime/runner/chart-set-lock.d.ts +4 -1
  11. package/dist/runtime/runner/chart-set-lock.d.ts.map +1 -1
  12. package/dist/runtime/runner/chart-set-lock.js +39 -4
  13. package/dist/runtime/runner/chart-set-lock.js.map +1 -1
  14. package/edition/README.md +69 -32
  15. package/edition/build-biome-index.mjs +1 -1
  16. package/edition/build-platform-service-index.mjs +1 -1
  17. package/edition/build-runtime-image-source-index.mjs +64 -20
  18. package/edition/catalogue-fetch.mjs +36 -9
  19. package/edition/catalogue-pin.mjs +71 -0
  20. package/edition/catalogue.mjs +11 -0
  21. package/edition/chart-set-source-commit.mjs +17 -7
  22. package/edition/checkout-indexed-source-repositories.mjs +17 -17
  23. package/edition/customer-flags.mjs +0 -1
  24. package/edition/develop-customer-edition.mjs +23 -5
  25. package/edition/develop-edition.mjs +147 -48
  26. package/edition/develop-freeze.mjs +69 -25
  27. package/edition/develop-seal.mjs +39 -25
  28. package/edition/dist-check.mjs +1 -1
  29. package/edition/edition-artifact.mjs +65 -18
  30. package/edition/edition-biome-manifests.mjs +2 -3
  31. package/edition/edition-chart-set.mjs +59 -6
  32. package/edition/edition-config.mjs +28 -2
  33. package/edition/edition-constants.mjs +10 -4
  34. package/edition/edition-contract-parse.mjs +52 -0
  35. package/edition/edition-contract.json +10 -1
  36. package/edition/edition-workspace.mjs +12 -9
  37. package/edition/evidence-trust-policy.mjs +26 -0
  38. package/edition/external-source-walk.mjs +48 -61
  39. package/edition/git-source-auth.mjs +104 -25
  40. package/edition/image-evidence.mjs +20 -10
  41. package/edition/kernel-contract-authority.mjs +23 -1
  42. package/edition/lib.mjs +13 -24
  43. package/edition/pin-source.mjs +6 -1
  44. package/edition/registry-credentials.mjs +11 -1
  45. package/edition/release-edition-artifact.mjs +3 -3
  46. package/edition/resolve-chart-set.mjs +50 -30
  47. package/edition/resolve-customer-edition.mjs +63 -7
  48. package/edition/resolve-distribution.mjs +1 -1
  49. package/edition/resolve-edition.mjs +12 -11
  50. package/edition/resolve-images.mjs +36 -15
  51. package/edition/seal-image-digests.mjs +31 -7
  52. package/edition/source-closure.mjs +1 -2
  53. package/edition/trust-policy-arming-verb.mjs +68 -0
  54. package/package.json +3 -3
@@ -114,7 +114,9 @@ import { join } from 'node:path';
114
114
 
115
115
  import { sealLock, verifyBiomeContentHashes } from './biome-content.mjs';
116
116
  import { fetchCatalogue } from './catalogue-fetch.mjs';
117
- import { CATALOGUE_FLAG, CATALOGUE_TOKEN_ENV_FLAG, CATALOGUE_USERNAME_FLAG } from './customer-flags.mjs';
117
+ import { readCataloguePin } from './catalogue-pin.mjs';
118
+ import { CATALOGUE_TOKEN_ENV_FLAG, CATALOGUE_USERNAME_FLAG, DEFINITION_FLAG } from './customer-flags.mjs';
119
+ import { EditionChannel } from './edition-constants.mjs';
118
120
  import { WorkspaceRoot, configureEditionWorkspaceFromProcess, editionsRoot, isEntryModule, runtimeImageSourceIndexPath } from './edition-workspace.mjs';
119
121
  import {
120
122
  assertCoordinatesFinal,
@@ -134,7 +136,20 @@ import {
134
136
  } from './verify-image-platforms.mjs';
135
137
 
136
138
  if (isEntryModule(import.meta.url)) {
137
- configureEditionWorkspaceFromProcess([WorkspaceRoot.Data, WorkspaceRoot.Editions, WorkspaceRoot.Sources, WorkspaceRoot.Kernel, WorkspaceRoot.Cache, WorkspaceRoot.SourceHash]);
139
+ // The customer form (it names --definition) reads exactly these roots - the data root (the vendor's
140
+ // runtime-image-source-index.json), the editions root, the sources root (the readability check of the
141
+ // vendor repositories), the kernel and the cache (external source trees) - and refuses any other.
142
+ let namesDefinition;
143
+ try {
144
+ namesDefinition = parseSealArgs(process.argv.slice(2)).catalogueFlags.has(DEFINITION_FLAG);
145
+ } catch (error) {
146
+ process.stderr.write(`${error.message}\n`);
147
+ process.exit(1);
148
+ }
149
+ configureEditionWorkspaceFromProcess(
150
+ [WorkspaceRoot.Data, WorkspaceRoot.Editions, WorkspaceRoot.Sources, WorkspaceRoot.Kernel, WorkspaceRoot.Cache],
151
+ { refuseOthers: namesDefinition },
152
+ );
138
153
  }
139
154
 
140
155
  const SHA256_DIGEST = /^sha256:[a-f0-9]{64}$/u;
@@ -393,12 +408,19 @@ export function isNotPublishedYet(error) {
393
408
  */
394
409
  export function parseSealArgs(args) {
395
410
  const MODES = new Set(['--check', '--if-published', '--publication-verdict']);
396
- const CATALOGUE_VALUE_FLAGS = new Set([CATALOGUE_FLAG, CATALOGUE_USERNAME_FLAG, CATALOGUE_TOKEN_ENV_FLAG]);
411
+ const CATALOGUE_VALUE_FLAGS = new Set([DEFINITION_FLAG, CATALOGUE_USERNAME_FLAG, CATALOGUE_TOKEN_ENV_FLAG]);
397
412
  const positional = [];
398
413
  const catalogueFlags = new Map();
399
414
  for (let i = 0; i < args.length; i += 1) {
400
415
  const arg = args[i];
401
416
  if (MODES.has(arg)) {continue;}
417
+ const eq = arg.indexOf('=');
418
+ if (eq > 0 && CATALOGUE_VALUE_FLAGS.has(arg.slice(0, eq))) {
419
+ const value = arg.slice(eq + 1);
420
+ if (value === '' || value.startsWith('--')) {throw new Error(`${arg.slice(0, eq)} takes a value`);}
421
+ catalogueFlags.set(arg.slice(0, eq), value);
422
+ continue;
423
+ }
402
424
  if (CATALOGUE_VALUE_FLAGS.has(arg)) {
403
425
  if (args[i + 1] === undefined || args[i + 1].startsWith('--')) {throw new Error(`${arg} takes a value`);}
404
426
  catalogueFlags.set(arg, args[i + 1]);
@@ -530,7 +552,7 @@ async function main() {
530
552
  throw new Error(
531
553
  'usage: xema edition seal <distributionId> ' +
532
554
  `[--check | --if-published | --publication-verdict] ` +
533
- `[--catalogue oci://<repository>@sha256:<digest> [--catalogue-username <name> --catalogue-token-env <VAR>]]`,
555
+ `[--definition <file> [--catalogue-username <name> --catalogue-token-env <VAR>]]`,
534
556
  );
535
557
  }
536
558
  // The modes answer different questions and combining them would make the
@@ -621,12 +643,14 @@ async function main() {
621
643
  // `authTokenEnv` and the test reads which variable the refusal names, because
622
644
  // no structural check can tell a threaded argument from an omitted one.
623
645
  const root = editionsRoot();
624
- // CUSTOMER MODE: the digest-pinned catalogue the edition was resolved against.
646
+ // CUSTOMER MODE (`--definition`): the digest-pinned RELEASE catalogue of catalogue.pin.json beside the
647
+ // definition, the one the edition was resolved against.
625
648
  // Its vendor biomes' tree ids are inputs on ITS authority (biome-content.mjs).
626
649
  const fetched =
627
- catalogueFlags.has(CATALOGUE_FLAG)
650
+ catalogueFlags.has(DEFINITION_FLAG)
628
651
  ? await fetchCatalogue({
629
- ref: catalogueFlags.get(CATALOGUE_FLAG),
652
+ ref: readCataloguePin({ definitionFile: catalogueFlags.get(DEFINITION_FLAG), channel: EditionChannel.Release }),
653
+ channel: EditionChannel.Release,
630
654
  username: catalogueFlags.get(CATALOGUE_USERNAME_FLAG),
631
655
  tokenEnv: catalogueFlags.get(CATALOGUE_TOKEN_ENV_FLAG),
632
656
  })
@@ -2,7 +2,7 @@
2
2
  // `xema edition source-closure`: the source tree hash of one directory of a
3
3
  // source repository at an exact commit, with its workspace-package closure.
4
4
  //
5
- // usage: xema edition source-closure --repo <repo> --path <dir> --commit <40 hex> --sources-root <dir> --source-hash <dir> --kernel <dir>
5
+ // usage: xema edition source-closure --repo <repo> --path <dir> --commit <40 hex> --sources-root <dir> --kernel <dir>
6
6
  //
7
7
  // These are the facts a content coordinate is derived from. A consumer frames
8
8
  // them into its own coordinate; it never reads a git tree, a workspace graph
@@ -85,7 +85,6 @@ export function readSourceClosure({ repoDir, repo, directory, commit }) {
85
85
  function main() {
86
86
  const rest = configureEditionWorkspaceFromArgv(process.argv.slice(2), [
87
87
  WorkspaceRoot.Sources,
88
- WorkspaceRoot.SourceHash,
89
88
  // The hash implementation is held to the kernel it was built for.
90
89
  WorkspaceRoot.Kernel,
91
90
  ]);
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ // `xema edition arming`: is the data root's declared evidence trust policy ARMED
3
+ // on one channel?
4
+ //
5
+ // usage: xema edition arming --channel <release|develop> --data-root <dir> --kernel <dir>
6
+ // stdout: {"channel":"<channel>","state":"armed|unarmed|partial","unmet":["…"]}
7
+ // exit: 0 only when the state is armed; 1 for any other state (each unmet
8
+ // entry on stderr) or a policy that does not hold to its pin; 2 for a
9
+ // usage error. A data root that declares no policy is `unarmed`.
10
+ // It reads the policy the way `xema edition check` does and never writes.
11
+
12
+ import { EditionChannel } from './edition-channel.mjs';
13
+ import {
14
+ WorkspaceRoot,
15
+ configureEditionWorkspaceFromArgv,
16
+ isEntryModule,
17
+ } from './edition-workspace.mjs';
18
+ import { assessDeclaredTrustPolicyArming } from './evidence-trust-policy.mjs';
19
+ import { TrustPolicyArmingState } from './trust-policy-arming.mjs';
20
+
21
+ export const ARMING_USAGE = `usage: xema edition arming --channel <${Object.values(EditionChannel).join('|')}> --data-root <dir> --kernel <dir>`;
22
+
23
+ /** The process exit codes of the verb. */
24
+ export const ArmingExit = Object.freeze({ Armed: 0, NotArmed: 1, Usage: 2 });
25
+
26
+ /** The channel of `--channel <channel>` among `rest`; anything else is a usage error. */
27
+ export function parseArmingArgs(rest) {
28
+ if (rest.length !== 2 || rest[0] !== '--channel' || !Object.values(EditionChannel).includes(rest[1])) {
29
+ throw new Error(`--channel <${Object.values(EditionChannel).join('|')}> is required and nothing else is accepted (got ${rest.length === 0 ? 'nothing' : JSON.stringify(rest.join(' '))})`);
30
+ }
31
+ return { channel: rest[1] };
32
+ }
33
+
34
+ /**
35
+ * Judge the configured data root's policy on `channel`, writing the one JSON
36
+ * line to `stdout` and each unmet entry to `stderr`. Returns the exit code.
37
+ */
38
+ export async function runArming({ channel, locateVerifier, stdout = process.stdout, stderr = process.stderr }) {
39
+ let verdict;
40
+ try {
41
+ verdict = await assessDeclaredTrustPolicyArming({ channel, locateVerifier });
42
+ } catch (error) {
43
+ stderr.write(`arming: ${error.message}\n`);
44
+ return ArmingExit.NotArmed;
45
+ }
46
+ const { state, unmet } = verdict;
47
+ stdout.write(`${JSON.stringify({ channel, state, unmet })}\n`);
48
+ if (state === TrustPolicyArmingState.ARMED) {return ArmingExit.Armed;}
49
+ for (const entry of unmet) {stderr.write(`${entry}\n`);}
50
+ return ArmingExit.NotArmed;
51
+ }
52
+
53
+ async function main() {
54
+ let channel;
55
+ try {
56
+ const rest = configureEditionWorkspaceFromArgv(process.argv.slice(2), [WorkspaceRoot.Data, WorkspaceRoot.Kernel]);
57
+ ({ channel } = parseArmingArgs(rest));
58
+ } catch (error) {
59
+ process.stderr.write(`arming: ${error.message}\n${ARMING_USAGE}\n`);
60
+ process.exitCode = ArmingExit.Usage;
61
+ return;
62
+ }
63
+ process.exitCode = await runArming({ channel });
64
+ }
65
+
66
+ if (isEntryModule(import.meta.url)) {
67
+ await main();
68
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/xema",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/xema-dev/xema-cli.git",
@@ -51,6 +51,7 @@
51
51
  "@nestjs/platform-express": "^11.1.28",
52
52
  "@xemahq/biome-sdk": "^18.1.0",
53
53
  "@xemahq/biome-supply-chain": "^0.5.0",
54
+ "@xemahq/distribution-source-hash": "^0.3.0",
54
55
  "@xemahq/dsl": "^0.23.0",
55
56
  "@xemahq/identity-client": "^0.16.0",
56
57
  "@xemahq/contracts": "^0.76.0",
@@ -68,7 +69,6 @@
68
69
  "@types/jest": "^30.0.0",
69
70
  "@types/node": "25.2.3",
70
71
  "@xemahq/biome-host-api-client": "^0.3.31",
71
- "@xemahq/distribution-source-hash": "^0.3.0",
72
72
  "@xemahq/eslint-config": "^0.9.2",
73
73
  "esbuild": "0.28.2",
74
74
  "eslint": "^9.39.4",
@@ -92,6 +92,6 @@
92
92
  "typecheck": "tsc --noEmit"
93
93
  },
94
94
  "xemaRelease": {
95
- "sourceDigest": "sha256:c33104cb26add433525e6447c931da38c0fc51a552b7f61f59b293734aeeb23c"
95
+ "sourceDigest": "sha256:a0dc6a3fdb7cce15b031dcd04476f19924d13d36924070b1527af1fa613b258e"
96
96
  }
97
97
  }