@xemahq/xema 0.35.0 → 0.36.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.
@@ -62225,9 +62225,9 @@ var EDITION_LOCKS = Object.freeze([...EDITION_CONTRACT.locks]);
62225
62225
  var EDITION_FILES = Object.freeze([EDITION_DESCRIPTOR_FILE, ...EDITION_LOCKS]);
62226
62226
 
62227
62227
  // edition/lib.mjs
62228
+ var import_yaml = __toESM(require_dist(), 1);
62228
62229
  import { createRequire as createRequire4 } from "node:module";
62229
62230
  import { isIP } from "node:net";
62230
- var import_yaml = __toESM(require_dist(), 1);
62231
62231
 
62232
62232
  // edition/adapter-host-versions.mjs
62233
62233
  var BUNDLED_PACKAGES = Object.freeze(["@xemahq/contracts", "@xemahq/biome-sdk"]);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "artifactSha256": "sha256:6a1bb7ce2649255733671979ea5914287fde441ca5afc07eba451145401eccee",
3
+ "artifactSha256": "sha256:85a8f844799b403c2686b5f6fdbecaaa07f2edfcab348d0502b2e803040f66cc",
4
4
  "esbuild": {
5
5
  "version": "0.28.2"
6
6
  },
@@ -2383,229 +2383,229 @@
2383
2383
  },
2384
2384
  {
2385
2385
  "package": "@xemahq/xema",
2386
- "version": "0.35.0",
2386
+ "version": "0.36.1",
2387
2387
  "path": "edition/adapter-host-versions.mjs",
2388
2388
  "sha256": "sha256:1b7ebd3592f4da1225fba74aaba912e7d85fbceeb1626f7dcdac83491cbb4d69"
2389
2389
  },
2390
2390
  {
2391
2391
  "package": "@xemahq/xema",
2392
- "version": "0.35.0",
2392
+ "version": "0.36.1",
2393
2393
  "path": "edition/authorization-base.mjs",
2394
2394
  "sha256": "sha256:bbeac7ff01376cb89ed2140526d4795d8e559b3f01612b404a701f19aaa24c6a"
2395
2395
  },
2396
2396
  {
2397
2397
  "package": "@xemahq/xema",
2398
- "version": "0.35.0",
2398
+ "version": "0.36.1",
2399
2399
  "path": "edition/build-ledger.mjs",
2400
2400
  "sha256": "sha256:05202cbdd606aee086c8e9c62d28be68c429653a8b1d73a289ed0fe4ff14da85"
2401
2401
  },
2402
2402
  {
2403
2403
  "package": "@xemahq/xema",
2404
- "version": "0.35.0",
2404
+ "version": "0.36.1",
2405
2405
  "path": "edition/connector-source-authority.mjs",
2406
2406
  "sha256": "sha256:ea94475f4324737673accd7de1303c44db1cbc4dac61a865a06cd83abe310164"
2407
2407
  },
2408
2408
  {
2409
2409
  "package": "@xemahq/xema",
2410
- "version": "0.35.0",
2410
+ "version": "0.36.1",
2411
2411
  "path": "edition/distribution-paths.mjs",
2412
2412
  "sha256": "sha256:d78a5c8405bc6c25d36fcec61b0030e1fdacac7d528e698adb96f906f4b70279"
2413
2413
  },
2414
2414
  {
2415
2415
  "package": "@xemahq/xema",
2416
- "version": "0.35.0",
2416
+ "version": "0.36.1",
2417
2417
  "path": "edition/edition-artifact.mjs",
2418
2418
  "sha256": "sha256:287e4cf042626963e07396c706350e9668adbcacd238a7ad4db1d68bba3858b2"
2419
2419
  },
2420
2420
  {
2421
2421
  "package": "@xemahq/xema",
2422
- "version": "0.35.0",
2422
+ "version": "0.36.1",
2423
2423
  "path": "edition/edition-channel.mjs",
2424
2424
  "sha256": "sha256:3c0c1564dc50be133cad500452d953353aa5beb703142c05a17bbce8175ba9f3"
2425
2425
  },
2426
2426
  {
2427
2427
  "package": "@xemahq/xema",
2428
- "version": "0.35.0",
2428
+ "version": "0.36.1",
2429
2429
  "path": "edition/edition-chart-set.mjs",
2430
- "sha256": "sha256:cea98292ffc8bfe2afcc01f327172bc9071a83ef9b62a4e56236f2029d2699a9"
2430
+ "sha256": "sha256:f9f16b58279c8c2619a39c5cc92bdbc334543d1a324304cd5d3b120d66dc8f3a"
2431
2431
  },
2432
2432
  {
2433
2433
  "package": "@xemahq/xema",
2434
- "version": "0.35.0",
2434
+ "version": "0.36.1",
2435
2435
  "path": "edition/edition-config.mjs",
2436
2436
  "sha256": "sha256:e3997bd9a0082e02d01760868b2a4f41ed3081e904126b30fdf86e7938dc6137"
2437
2437
  },
2438
2438
  {
2439
2439
  "package": "@xemahq/xema",
2440
- "version": "0.35.0",
2440
+ "version": "0.36.1",
2441
2441
  "path": "edition/edition-constants.mjs",
2442
2442
  "sha256": "sha256:71ae51028847ab3430ffec9b229b0516a7705b75a6de1fcfa665f5e1abf8e9bb"
2443
2443
  },
2444
2444
  {
2445
2445
  "package": "@xemahq/xema",
2446
- "version": "0.35.0",
2446
+ "version": "0.36.1",
2447
2447
  "path": "edition/edition-contract-parse.mjs",
2448
2448
  "sha256": "sha256:c575e96b70bda82899931eb0b18567988e2e13e664fa498bcbef96b571dcabb4"
2449
2449
  },
2450
2450
  {
2451
2451
  "package": "@xemahq/xema",
2452
- "version": "0.35.0",
2452
+ "version": "0.36.1",
2453
2453
  "path": "edition/edition-contract.json",
2454
2454
  "sha256": "sha256:aa1a05f1728813a7bdb1e02d9305e9adf641d695e6767305210c67a1d81b38a7"
2455
2455
  },
2456
2456
  {
2457
2457
  "package": "@xemahq/xema",
2458
- "version": "0.35.0",
2458
+ "version": "0.36.1",
2459
2459
  "path": "edition/edition-protocol.mjs",
2460
2460
  "sha256": "sha256:c488ac72ff3f23c0f28f8db159bf84d2c86ec5cda3633db1fe91ca3f21b12214"
2461
2461
  },
2462
2462
  {
2463
2463
  "package": "@xemahq/xema",
2464
- "version": "0.35.0",
2464
+ "version": "0.36.1",
2465
2465
  "path": "edition/edition-source-pins.mjs",
2466
2466
  "sha256": "sha256:b141474fff33b06734fb62cd2552752b991c8267bb1c9bccb22a81dd80e91c6c"
2467
2467
  },
2468
2468
  {
2469
2469
  "package": "@xemahq/xema",
2470
- "version": "0.35.0",
2470
+ "version": "0.36.1",
2471
2471
  "path": "edition/edition-workspace.mjs",
2472
- "sha256": "sha256:22235719a41c0cf6206f5bcd7489341dccb22150df0b129724ef8ab566b5bff1"
2472
+ "sha256": "sha256:18ba727e6b13ca252def25cc6bd9adf894cbc2018198c41ce522637eeac7f871"
2473
2473
  },
2474
2474
  {
2475
2475
  "package": "@xemahq/xema",
2476
- "version": "0.35.0",
2476
+ "version": "0.36.1",
2477
2477
  "path": "edition/evidence-checkout.mjs",
2478
2478
  "sha256": "sha256:31fb669769b31de4c6f2b2501bb96959548172ef166e7568edbbfed7f5079a11"
2479
2479
  },
2480
2480
  {
2481
2481
  "package": "@xemahq/xema",
2482
- "version": "0.35.0",
2482
+ "version": "0.36.1",
2483
2483
  "path": "edition/evidence-grammars.mjs",
2484
2484
  "sha256": "sha256:4dae22b61ade99219a482b971c9780d68a3d37d021e39cdfe860b245364b8b9f"
2485
2485
  },
2486
2486
  {
2487
2487
  "package": "@xemahq/xema",
2488
- "version": "0.35.0",
2488
+ "version": "0.36.1",
2489
2489
  "path": "edition/evidence-trust-pin.mjs",
2490
2490
  "sha256": "sha256:b9dd5c01903394436530783614efb0cd357d982ed2befd844a39328479773cbc"
2491
2491
  },
2492
2492
  {
2493
2493
  "package": "@xemahq/xema",
2494
- "version": "0.35.0",
2494
+ "version": "0.36.1",
2495
2495
  "path": "edition/git-json.mjs",
2496
2496
  "sha256": "sha256:d0d25cda0c19007becabc9a2827c3dcf759b295cd0b41596eb4480c9549a1f21"
2497
2497
  },
2498
2498
  {
2499
2499
  "package": "@xemahq/xema",
2500
- "version": "0.35.0",
2500
+ "version": "0.36.1",
2501
2501
  "path": "edition/image-delivery-entitlement-descriptor.mjs",
2502
2502
  "sha256": "sha256:4726b66116f01bf2523fafe2b7a356591eca8fb5ca6bd8b154dd4821873e921b"
2503
2503
  },
2504
2504
  {
2505
2505
  "package": "@xemahq/xema",
2506
- "version": "0.35.0",
2506
+ "version": "0.36.1",
2507
2507
  "path": "edition/image-evidence-replay-state.mjs",
2508
2508
  "sha256": "sha256:eba0cf1d38af0ab2f00c5099fa8bc2edc543136ce92f895544d4d284b3d6af0f"
2509
2509
  },
2510
2510
  {
2511
2511
  "package": "@xemahq/xema",
2512
- "version": "0.35.0",
2512
+ "version": "0.36.1",
2513
2513
  "path": "edition/image-evidence.mjs",
2514
2514
  "sha256": "sha256:433202eb2db84510acd11de6fe5ede81c8d96b8bc72991444940f7f84a48897f"
2515
2515
  },
2516
2516
  {
2517
2517
  "package": "@xemahq/xema",
2518
- "version": "0.35.0",
2518
+ "version": "0.36.1",
2519
2519
  "path": "edition/kernel-capability-domain.mjs",
2520
2520
  "sha256": "sha256:3ecf887dd8d399e91a8285f6f115f6e418fb59bbf3f004539fe65ec667219356"
2521
2521
  },
2522
2522
  {
2523
2523
  "package": "@xemahq/xema",
2524
- "version": "0.35.0",
2524
+ "version": "0.36.1",
2525
2525
  "path": "edition/kernel-contract-authority.mjs",
2526
2526
  "sha256": "sha256:20abdde62a7b037c01ea9bbe1ff1e6094e6b0efd0add2f656f1938a04409bf82"
2527
2527
  },
2528
2528
  {
2529
2529
  "package": "@xemahq/xema",
2530
- "version": "0.35.0",
2530
+ "version": "0.36.1",
2531
2531
  "path": "edition/lib.mjs",
2532
- "sha256": "sha256:9708d6d385f69105bbd77359f5571ffec7b0c7f7fd343c4bbb88b33c4a61e780"
2532
+ "sha256": "sha256:dfcfdc0716b63f91db88364c4fecc2f8941511b302a20429fd5921270e375cb6"
2533
2533
  },
2534
2534
  {
2535
2535
  "package": "@xemahq/xema",
2536
- "version": "0.35.0",
2536
+ "version": "0.36.1",
2537
2537
  "path": "edition/no-follow-file.mjs",
2538
2538
  "sha256": "sha256:c17bdf5e441f3c079aa06d4b48bbed05cad087855b9ad2a5e6dc43d5ee2b17c3"
2539
2539
  },
2540
2540
  {
2541
2541
  "package": "@xemahq/xema",
2542
- "version": "0.35.0",
2542
+ "version": "0.36.1",
2543
2543
  "path": "edition/operation-requirements.mjs",
2544
2544
  "sha256": "sha256:ffe6fdc9da6b2974270fc86c11be0c41d0bc6d85c8e3c137d3c3bc00a72fc4f6"
2545
2545
  },
2546
2546
  {
2547
2547
  "package": "@xemahq/xema",
2548
- "version": "0.35.0",
2548
+ "version": "0.36.1",
2549
2549
  "path": "edition/pin-source.mjs",
2550
2550
  "sha256": "sha256:a23fef4698ef66ba9de4a1aabe3eebe6487d1f105f3fc161bafc5a33b99a2440"
2551
2551
  },
2552
2552
  {
2553
2553
  "package": "@xemahq/xema",
2554
- "version": "0.35.0",
2554
+ "version": "0.36.1",
2555
2555
  "path": "edition/source-authority.mjs",
2556
2556
  "sha256": "sha256:858b607dde94e2abd00a341f569e18cfa567d4bff139c64a2d60abbb7de4c85e"
2557
2557
  },
2558
2558
  {
2559
2559
  "package": "@xemahq/xema",
2560
- "version": "0.35.0",
2560
+ "version": "0.36.1",
2561
2561
  "path": "edition/strict-json.mjs",
2562
2562
  "sha256": "sha256:f95778396df7f38b086f55d2ec4f3b6644a8aeff2b32282a62829145fb544562"
2563
2563
  },
2564
2564
  {
2565
2565
  "package": "@xemahq/xema",
2566
- "version": "0.35.0",
2566
+ "version": "0.36.1",
2567
2567
  "path": "edition/string-order.mjs",
2568
2568
  "sha256": "sha256:b3210cd273e4b2e01fb8b1a91e28734cd211d4010c080d0ce95f5e5ff631cffb"
2569
2569
  },
2570
2570
  {
2571
2571
  "package": "@xemahq/xema",
2572
- "version": "0.35.0",
2572
+ "version": "0.36.1",
2573
2573
  "path": "edition/trusted-executable.mjs",
2574
2574
  "sha256": "sha256:37d46cdbc999ddd55d4ea8aeed4850ddd1efde89ed7b532f5a2ddec87105d796"
2575
2575
  },
2576
2576
  {
2577
2577
  "package": "@xemahq/xema",
2578
- "version": "0.35.0",
2578
+ "version": "0.36.1",
2579
2579
  "path": "edition/verifier-binding.mjs",
2580
2580
  "sha256": "sha256:80732658617f5255258c538eeb2383331ec8553b44b58d552b567845a7b916aa"
2581
2581
  },
2582
2582
  {
2583
2583
  "package": "@xemahq/xema",
2584
- "version": "0.35.0",
2584
+ "version": "0.36.1",
2585
2585
  "path": "edition/verifier-files.mjs",
2586
2586
  "sha256": "sha256:cdd14a20a63f0f194a8abb55680a5a7e3ced1f09f8b210a90d349e655f6de0c0"
2587
2587
  },
2588
2588
  {
2589
2589
  "package": "@xemahq/xema",
2590
- "version": "0.35.0",
2590
+ "version": "0.36.1",
2591
2591
  "path": "edition/verifier-provenance.mjs",
2592
2592
  "sha256": "sha256:3e2fb8e07cf1f66b8ad6c7ac2555fe3af64ec7abeb07cecbaf1939a18c2b3663"
2593
2593
  },
2594
2594
  {
2595
2595
  "package": "@xemahq/xema",
2596
- "version": "0.35.0",
2596
+ "version": "0.36.1",
2597
2597
  "path": "edition/verify-image-evidence.mjs",
2598
2598
  "sha256": "sha256:62f83f8bb835f360535402d12657156d2c9d6e651b426c2b30a04a2dc2f8d3e8"
2599
2599
  },
2600
2600
  {
2601
2601
  "package": "@xemahq/xema",
2602
- "version": "0.35.0",
2602
+ "version": "0.36.1",
2603
2603
  "path": "edition/workspace-sections.mjs",
2604
2604
  "sha256": "sha256:058c849767434e9ba911d9310092bede42e3ef959c75bbd35ff8879dc21ce3ff"
2605
2605
  },
2606
2606
  {
2607
2607
  "package": "@xemahq/xema",
2608
- "version": "0.35.0",
2608
+ "version": "0.36.1",
2609
2609
  "path": "scripts/build-evidence-verifier.mjs",
2610
2610
  "sha256": "sha256:5a688d20c47dc88aff37aa0c6cc02daf2c370a5bc610fef8446ce7be222d4c0b"
2611
2611
  },
@@ -0,0 +1,96 @@
1
+ // develop-chart-roster — the develop chart roster of a deploy checkout, as the
2
+ // deploy repository itself computes it.
3
+ //
4
+ // A develop chart's version is `0.0.0-h<16 hex>`, the first 16 hex of its full
5
+ // content digest (xema-deploy scripts/lib/chart-content-digest.mjs,
6
+ // developChartVersionFromDigest). That function belongs to the deploy
7
+ // repository, and so does the index version derived from the roster: publish-
8
+ // charts on refs/heads/develop runs the same code to publish the charts and
9
+ // close the set with its `xema-chart-set` index. So the CLI never reimplements
10
+ // or vendors it: it runs the entry point of the frozen deploy checkout
11
+ // (`scripts/chart-content-digest.mjs --develop-roster --json`), which is the
12
+ // code the publisher ran for that commit, and validates the one document it
13
+ // prints. A vendored copy would pin the CLI to one revision of a hash whose
14
+ // owner is the deploy commit being resolved.
15
+
16
+ import { execFileSync } from 'node:child_process';
17
+ import { join } from 'node:path';
18
+
19
+ import { parseStrictJson } from './strict-json.mjs';
20
+
21
+ /** The schema string the deploy entry point stamps on its develop roster. */
22
+ export const DEVELOP_CHART_ROSTER_SCHEMA = 'xema-develop-chart-roster/1';
23
+
24
+ /** The entry point, relative to the deploy checkout, and its arguments. */
25
+ export const DEVELOP_CHART_ROSTER_ENTRY = 'scripts/chart-content-digest.mjs';
26
+ export const DEVELOP_CHART_ROSTER_ARGS = Object.freeze(['--develop-roster', '--json']);
27
+
28
+ /** A develop channel coordinate: revision 0 and the content digest's first 16 hex. */
29
+ export const DEVELOP_CHART_VERSION_PATTERN = /^0\.0\.0-h[0-9a-f]{16}$/;
30
+
31
+ /** A chart name as Helm and the registry address it. */
32
+ const CHART_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
33
+
34
+ const ROSTER_KEYS = 'indexVersion,members,schema';
35
+ const MEMBER_KEYS = 'name,version';
36
+
37
+ /**
38
+ * Validate the develop roster document `document` (from `source`) and return
39
+ * `{indexVersion, members: [{name, version}]}`. Every rule is strict: the exact
40
+ * schema string and keys, develop coordinates only, and members sorted by name
41
+ * with no name twice.
42
+ */
43
+ export function parseDevelopChartRoster(document, source) {
44
+ const fail = (why) => {
45
+ throw new Error(`${source} is not a ${DEVELOP_CHART_ROSTER_SCHEMA} roster: ${why}`);
46
+ };
47
+ if (!document || typeof document !== 'object' || Array.isArray(document)) {fail('it is not a JSON object');}
48
+ if (document.schema !== DEVELOP_CHART_ROSTER_SCHEMA) {fail(`schema must be "${DEVELOP_CHART_ROSTER_SCHEMA}" (got ${JSON.stringify(document.schema)})`);}
49
+ const keys = Object.keys(document).sort().join(',');
50
+ if (keys !== ROSTER_KEYS) {fail(`it must carry exactly ${ROSTER_KEYS} (got ${keys})`);}
51
+ if (!DEVELOP_CHART_VERSION_PATTERN.test(String(document.indexVersion))) {
52
+ fail(`indexVersion must be a develop coordinate 0.0.0-h<16 hex> (got ${JSON.stringify(document.indexVersion)})`);
53
+ }
54
+ if (!Array.isArray(document.members) || document.members.length === 0) {fail('members must be a non-empty array');}
55
+ let previous = '';
56
+ const members = document.members.map((member, position) => {
57
+ if (!member || typeof member !== 'object' || Array.isArray(member) || Object.keys(member).sort().join(',') !== MEMBER_KEYS) {
58
+ fail(`member ${position} must be exactly {name, version}`);
59
+ }
60
+ if (!CHART_NAME_PATTERN.test(String(member.name))) {fail(`member ${position} has a malformed chart name ${JSON.stringify(member.name)}`);}
61
+ if (!DEVELOP_CHART_VERSION_PATTERN.test(String(member.version))) {
62
+ fail(`${member.name} has no develop coordinate 0.0.0-h<16 hex> (got ${JSON.stringify(member.version)})`);
63
+ }
64
+ if (member.name <= previous) {fail(`members must be sorted by name with no name twice (${member.name} follows ${previous})`);}
65
+ previous = member.name;
66
+ return { name: member.name, version: member.version };
67
+ });
68
+ return { indexVersion: document.indexVersion, members };
69
+ }
70
+
71
+ /**
72
+ * The develop roster of the deploy checkout at `deployDir`: its own entry point
73
+ * run with this node, in that checkout, with only PATH from the environment (the
74
+ * entry point needs git and nothing else; no credential reaches it).
75
+ */
76
+ export function readDevelopChartRoster(deployDir) {
77
+ const entry = join(deployDir, DEVELOP_CHART_ROSTER_ENTRY);
78
+ let stdout;
79
+ try {
80
+ stdout = execFileSync(process.execPath, [entry, ...DEVELOP_CHART_ROSTER_ARGS], {
81
+ cwd: deployDir,
82
+ encoding: 'utf8',
83
+ env: { PATH: process.env.PATH ?? '' },
84
+ maxBuffer: 16 * 1024 * 1024,
85
+ stdio: ['ignore', 'pipe', 'pipe'],
86
+ });
87
+ } catch (error) {
88
+ const stderr = typeof error?.stderr === 'string' ? error.stderr.trim() : '';
89
+ throw new Error(
90
+ `the deploy checkout's develop roster failed (node ${DEVELOP_CHART_ROSTER_ENTRY} ${DEVELOP_CHART_ROSTER_ARGS.join(' ')} in ${deployDir}): ${stderr || error.message}`,
91
+ { cause: error },
92
+ );
93
+ }
94
+ const source = `${DEVELOP_CHART_ROSTER_ENTRY} ${DEVELOP_CHART_ROSTER_ARGS.join(' ')}`;
95
+ return parseDevelopChartRoster(parseStrictJson(stdout, source), source);
96
+ }
@@ -1,61 +1,112 @@
1
1
  // develop-chart-set — the chart-set lock of a develop edition.
2
2
  //
3
- // A develop edition renders with the charts the publisher actually published:
4
- // the committed release chart-set lock's entries (names, content versions and
5
- // digests, and each index digest), unchanged. xema-deploy publishes charts per
6
- // content version (`<n>-h<16 hex>`) for the commit its release set was closed
7
- // at, so that commit is the only deploy commit whose charts exist in the
8
- // registry. A develop edition frozen at that commit takes the release lock
9
- // as it is, and asks the registry nothing about a chart's tag; a develop edition
10
- // frozen at any other commit is refused, because no chart was published for it
11
- // (a develop chart lane in xema-deploy is the owner's decision, not built).
3
+ // A develop edition renders the charts of its frozen deploy commit. The deploy
4
+ // checkout computes its own develop roster (develop-chart-roster.mjs: every
5
+ // chart at `0.0.0-h<16 hex>` and the set's index version), and xema-deploy
6
+ // publish-charts on refs/heads/develop publishes those charts and closes the
7
+ // set with a `xema-chart-set` index at that index version, the same artifact
8
+ // a release closes its set with. So a develop lock is resolved exactly as a
9
+ // release one is (resolve-chart-set.mjs), only at a version the deploy commit
10
+ // names instead of the newest the registry holds: read the index at the
11
+ // roster's index version, require its members to be the roster, seal every
12
+ // member against the registry, and build the same schemaVersion 4 lock. The
13
+ // committed release lock is never read.
14
+ //
15
+ // ONE PUBLISHER. A develop lock lists only the publisher whose repository is
16
+ // the deploy pin role's: a develop deployment renders no infra chart (the
17
+ // deploy engine refuses scope infra on the develop channel), and the other
18
+ // publishers have no develop channel.
19
+ //
20
+ // NOT PUBLISHED IS A REFUSAL. An index or member the registry does not serve
21
+ // (404) is refused by name and version: publish-charts for the deploy commit
22
+ // has not finished green. There is no fallback to any other set.
12
23
 
13
24
  import { basename } from 'node:path';
14
25
 
15
- import { chartSetSourceCommits } from './chart-set-source-commit.mjs';
26
+ import { readDevelopChartRoster } from './develop-chart-roster.mjs';
16
27
  import { assertRosteredChartSetLock } from './edition-chart-set.mjs';
28
+ import { deployRoot } from './edition-workspace.mjs';
17
29
  import { COMMIT_PATTERN } from './evidence-grammars.mjs';
18
30
  import { deployPinKey } from './pin-source.mjs';
19
- import { CHART_SET_LOCK_FILE, chartRegistryClient, chartSetLockPath, readLock } from './resolve-chart-set.mjs';
31
+ import {
32
+ CHART_SET_LOCK_FILE,
33
+ buildLock,
34
+ chartRegistryClient,
35
+ chartSetPublishers,
36
+ indexRosterAndDigest,
37
+ registryChartDigest,
38
+ sealRoster,
39
+ } from './resolve-chart-set.mjs';
20
40
 
21
- /** The source commits of `lock`'s publishers, read from their index charts at the digests the lock pins. */
22
- const registrySourceCommits = (lock) => chartSetSourceCommits({ client: chartRegistryClient(), lock });
41
+ const NOT_FOUND = 404;
23
42
 
24
- /**
25
- * The develop chart-set lock for the deploy commit `xemaDeploySha`: the committed
26
- * release lock, when that lock's deploy publisher closed its set at this commit.
27
- * `readSourceCommits(lock)` defaults to the chart registry's index charts and
28
- * returns `{publishers: [{repo, sourceCommit}]}`.
29
- *
30
- * TEMPORARY BRIDGE (owner: edition, lead D41 10-13): only the release set's
31
- * source commit is resolvable here. Exit: develop charts resolved by content
32
- * version (edition T37: the shared developChartVersionFromDigest, published by
33
- * xema-deploy publish-charts on develop pushes), which replaces this function
34
- * before t348-i2 lands.
35
- */
36
- export async function resolveDevelopChartSet({ xemaDeploySha, releaseLock = readLock(), readSourceCommits = registrySourceCommits }) {
37
- if (!COMMIT_PATTERN.test(xemaDeploySha ?? '')) {
38
- throw new Error(`the deploy checkout SHA is not a 40-hex commit: ${JSON.stringify(xemaDeploySha)}`);
39
- }
40
- if (releaseLock === null) {
41
- throw new Error(`${chartSetLockPath()} is missing or is not JSON: run 'xema edition chart-set resolve' first`);
42
- }
43
- assertRosteredChartSetLock(releaseLock, CHART_SET_LOCK_FILE);
43
+ /** The publisher whose repository is the deploy pin role's; exactly one must be configured. */
44
+ function deployPublisher() {
44
45
  const deployRepo = basename(deployPinKey());
45
- const deployPublishers = releaseLock.publishers.filter((publisher) => basename(publisher.repo) === deployRepo);
46
- if (deployPublishers.length !== 1) {
46
+ const publishers = chartSetPublishers().filter((publisher) => basename(publisher.repo) === deployRepo);
47
+ if (publishers.length !== 1) {
47
48
  throw new Error(
48
- `${deployPublishers.length} chart publishers of ${CHART_SET_LOCK_FILE} have repository ${deployRepo} (the deploy pin role); exactly one must, ` +
49
- 'since its source commit is the one commit whose charts were published',
49
+ `${publishers.length} configured chart publishers have repository ${deployRepo} (the deploy pin role); exactly one must, ` +
50
+ 'since a develop chart set is that publisher\'s set at the deploy commit',
50
51
  );
51
52
  }
52
- const { sourceCommit } = (await readSourceCommits(releaseLock)).publishers.find((publisher) => publisher.index === deployPublishers[0].index) ?? {};
53
- if (sourceCommit !== xemaDeploySha) {
53
+ return publishers[0];
54
+ }
55
+
56
+ /** Run `read`; a registry 404 becomes the "not published yet" refusal naming `what` and the publisher's run for the deploy commit. */
57
+ async function published(read, what, { publisher, xemaDeploySha }) {
58
+ try {
59
+ return await read();
60
+ } catch (error) {
61
+ if (error?.status !== NOT_FOUND) {throw error;}
62
+ throw new Error(`${what} is not published yet; ${publisher.repo} publish-charts for ${xemaDeploySha} not green`, { cause: error });
63
+ }
64
+ }
65
+
66
+ /** Refuse an index whose members are not exactly the roster's names at the roster's versions. */
67
+ function assertIndexIsRoster(indexRoster, members, label) {
68
+ const expected = members.map(({ name, version }) => `${name} ${version}`);
69
+ const actual = Object.entries(indexRoster).map(([name, member]) => `${name} ${member.version}`);
70
+ const missing = expected.filter((line) => !actual.includes(line));
71
+ const extra = actual.filter((line) => !expected.includes(line));
72
+ if (missing.length > 0 || extra.length > 0) {
54
73
  throw new Error(
55
- `the develop deploy commit ${xemaDeploySha} is not the commit ${CHART_SET_LOCK_FILE} was published from (${sourceCommit}): ` +
56
- 'develop charts are only published for the release set\'s source commit, so no chart exists for this commit. ' +
57
- 'A develop chart lane in the deploy repository is required to develop at another commit (owner decision, not built)',
74
+ `${label} does not carry the deploy checkout's develop roster: ` +
75
+ `missing [${missing.join(', ')}], unexpected [${extra.join(', ')}]`,
58
76
  );
59
77
  }
60
- return releaseLock;
78
+ }
79
+
80
+ /**
81
+ * The develop chart-set lock for the deploy commit `xemaDeploySha`, whose frozen
82
+ * checkout is `deployDir`. `readRoster(deployDir)` returns `{indexVersion, members}`;
83
+ * `client` is the chart registry client the release resolver uses.
84
+ */
85
+ export async function resolveDevelopChartSet({ xemaDeploySha, deployDir = deployRoot(), readRoster = readDevelopChartRoster, client }) {
86
+ if (!COMMIT_PATTERN.test(xemaDeploySha ?? '')) {
87
+ throw new Error(`the deploy checkout SHA is not a 40-hex commit: ${JSON.stringify(xemaDeploySha)}`);
88
+ }
89
+ const publisher = deployPublisher();
90
+ const { indexVersion, members } = readRoster(deployDir);
91
+ const registry = client ?? chartRegistryClient();
92
+ const label = `${publisher.index}@${indexVersion}`;
93
+ const { roster, indexDigest } = await published(
94
+ () => indexRosterAndDigest(registry, publisher.index, indexVersion),
95
+ `the chart-set index ${label}`,
96
+ { publisher, xemaDeploySha },
97
+ );
98
+ assertIndexIsRoster(roster, members, label);
99
+ const lookup = registryChartDigest(registry);
100
+ const charts = await sealRoster(
101
+ roster,
102
+ (name, version) => published(() => lookup(name, version), `chart ${name}:${version}`, { publisher, xemaDeploySha }),
103
+ label,
104
+ );
105
+ const lock = buildLock(
106
+ { [publisher.index]: indexVersion },
107
+ { [publisher.index]: charts },
108
+ { [publisher.index]: indexDigest },
109
+ [publisher],
110
+ );
111
+ return assertRosteredChartSetLock(lock, CHART_SET_LOCK_FILE);
61
112
  }
@@ -2,8 +2,8 @@
2
2
  //
3
3
  // The whole pipeline, in the order the release runs it, over the snapshot's
4
4
  // injected inputs: distribution lock -> authorization base (composed, never
5
- // written) -> images lock -> develop seal, plus the chart-set lock: the release
6
- // lock's published charts (develop-chart-set.mjs). Nothing here writes to the editions
5
+ // written) -> images lock -> develop seal, plus the chart-set lock: the frozen
6
+ // deploy commit's develop chart set (develop-chart-set.mjs). Nothing here writes to the editions
7
7
  // trees; the caller writes the artifact (edition-artifact.mjs).
8
8
 
9
9
  import { adapterHostRow, assertAdapterBundlesMatchHost, fetchRegistryManifest } from './adapter-bundled-versions.mjs';
@@ -21,7 +21,7 @@ import { composeAuthorizationBase, resolveDistributionWithIndex } from './resolv
21
21
  import { externalSourceTrees, resolveImages, sourceTreeLocator } from './resolve-images.mjs';
22
22
  import { createPinnedSourceAuthority } from './source-authority.mjs';
23
23
 
24
- export async function resolveDevelopEdition({ id, pins, env = process.env, sealOptions = {}, readSourceCommits, fetchKernelTarball, fetchManifest = fetchRegistryManifest }) {
24
+ export async function resolveDevelopEdition({ id, pins, env = process.env, sealOptions = {}, fetchKernelTarball, fetchManifest = fetchRegistryManifest }) {
25
25
  const schemas = await loadKernelDistributionSchemas();
26
26
  assertFrozenCheckouts(pins);
27
27
  const inputs = await buildSnapshotInputs({ id, pins, schemas });
@@ -40,10 +40,7 @@ export async function resolveDevelopEdition({ id, pins, env = process.env, sealO
40
40
  locate: sourceTreeLocator(externalSourceTrees(lock)),
41
41
  vendoredCommit: (repo) => authority.vendoredSourceCommitForRepository(repo),
42
42
  });
43
- const chartSetLock = await resolveDevelopChartSet({
44
- xemaDeploySha: pins[deployPinKey()],
45
- ...(readSourceCommits === undefined ? {} : { readSourceCommits }),
46
- });
43
+ const chartSetLock = await resolveDevelopChartSet({ xemaDeploySha: pins[deployPinKey()] });
47
44
  const sourceTreeIds = await biomeSourceTreeIds({
48
45
  schemas,
49
46
  lock,
@@ -38,7 +38,7 @@ export const EditionChartSetCheck = Object.freeze({
38
38
  STALE: 'stale',
39
39
  });
40
40
 
41
- /** A published chart's version coordinate: `-h<16 hex>`, the content hash its publisher mints. A develop chart set takes the release set's charts, so it carries the same coordinate. */
41
+ /** A published chart's version coordinate: `-h<16 hex>`, the content hash its publisher mints, on both channels (develop: `0.0.0-h<16 hex>`). */
42
42
  const CHART_VERSION_COORDINATE = /-h[0-9a-f]{16}$/;
43
43
 
44
44
  /** The chart-set lock schema every reader accepts; a lock of any other schema is re-resolved, never migrated. */
@@ -109,6 +109,8 @@ export const kernelDistPath = (...segments) =>
109
109
 
110
110
  export const biomeIndexPath = () => join(dataRoot(), 'biome-index.json');
111
111
  export const storePublisherIdentitiesPath = () => join(dataRoot(), 'store-publisher-identities.json');
112
+ export const storeSourceRepositoriesPath = () =>
113
+ join(dataRoot(), 'vendor-ops', 'store-source-repositories.json');
112
114
  export const platformServiceIndexPath = () =>
113
115
  join(dataRoot(), 'platform-service-index.json');
114
116
  export const runtimeImageSourceIndexPath = () =>
package/edition/lib.mjs CHANGED
@@ -12,7 +12,6 @@ import { execFileSync } from 'node:child_process';
12
12
  import { createHash } from 'node:crypto';
13
13
  import { createRequire } from 'node:module';
14
14
  import { isIP } from 'node:net';
15
- import { join } from 'node:path';
16
15
 
17
16
  import { parse as parseYaml } from 'yaml';
18
17
 
@@ -23,11 +22,11 @@ import {
23
22
  } from './connector-source-authority.mjs';
24
23
  import { assertKernelEditionProtocol } from './edition-protocol.mjs';
25
24
  import {
26
- dataRoot,
27
25
  kernelDistPath,
28
26
  kernelPackageDir,
29
27
  kernelRepoDir,
30
28
  sourcePath,
29
+ storeSourceRepositoriesPath,
31
30
  } from './edition-workspace.mjs';
32
31
  import { SHA256_HEX_PATTERN } from './evidence-grammars.mjs';
33
32
  import { readGitJsonAtCommit } from './git-json.mjs';
@@ -1021,11 +1020,19 @@ function isFixtureManifest(repoRelativePath) {
1021
1020
  }
1022
1021
 
1023
1022
  export function distributionBiomeSourceRepositories() {
1024
- const publishersPath = join(
1025
- dataRoot(),
1026
- 'store-publisher-identities.json',
1027
- );
1023
+ const publishersPath = storeSourceRepositoriesPath();
1028
1024
  const publishers = readStrictJsonFile(publishersPath);
1025
+ if (publishers.schemaVersion !== 1) {
1026
+ throw new Error(`${publishersPath} must declare schemaVersion 1`);
1027
+ }
1028
+ const unknownKeys = Object.keys(publishers).filter(
1029
+ (key) => key !== 'schemaVersion' && key !== 'publishers',
1030
+ );
1031
+ if (unknownKeys.length > 0) {
1032
+ throw new Error(
1033
+ `${publishersPath}: unknown top-level key ${unknownKeys.map((key) => JSON.stringify(key)).join(', ')}`,
1034
+ );
1035
+ }
1029
1036
  if (
1030
1037
  !Array.isArray(publishers.publishers) ||
1031
1038
  publishers.publishers.length === 0
@@ -96,7 +96,7 @@ export const chartSetLockPath = () => join(dataRoot(), CHART_SET_LOCK_FILE);
96
96
  * (edition-chart-set.mjs).
97
97
  */
98
98
  const chartRegistry = () => vendorChartSetConfig().chartRegistry;
99
- const chartSetPublishers = () => vendorChartSetConfig().chartPublishers;
99
+ export const chartSetPublishers = () => vendorChartSetConfig().chartPublishers;
100
100
 
101
101
  /** `<host>/<path>` -> the repository path the registry API addresses. */
102
102
  export function registryRepository(indexName) {
@@ -252,12 +252,15 @@ export async function manifestAnnotations(client, indexName, version, served) {
252
252
  }
253
253
 
254
254
  /** The roster and the served manifest digest of the index chart `<indexName>:<version>`, from ONE manifest read. */
255
- async function indexRosterAndDigest(client, indexName, version) {
255
+ export async function indexRosterAndDigest(client, indexName, version) {
256
256
  const served = await client.getManifestByTag(registryRepository(indexName), version);
257
257
  const annotations = await manifestAnnotations(client, indexName, version, served);
258
258
  return { roster: parseIndexRoster(annotations[INDEX_ROSTER_ANNOTATION], `${indexName}@${version}`), indexDigest: served.digest };
259
259
  }
260
260
 
261
+ /** The `sealRoster` lookup through `client`: the manifest digest the registry serves for `<name>:<version>`. */
262
+ export const registryChartDigest = (client) => async (name, version) => (await client.getManifestByTag(registryRepository(name), version)).digest;
263
+
261
264
  /** Every edition directory (one holding a distribution.lock.json) under the editions root. */
262
265
  function editionDirs() {
263
266
  return readdirSync(editionsRoot(), { withFileTypes: true })
@@ -320,11 +323,7 @@ export async function resolveFromRegistry(client = chartRegistryClient()) {
320
323
  indexDigestsByIndex[index] = indexDigest;
321
324
  // The registry is asked for every member, so an index digest is checked
322
325
  // against it and a member without one still gets sealed.
323
- rostersByIndex[index] = await sealRoster(
324
- roster,
325
- async (name, memberVersion) => (await client.getManifestByTag(registryRepository(name), memberVersion)).digest,
326
- `${index}@${version}`,
327
- );
326
+ rostersByIndex[index] = await sealRoster(roster, registryChartDigest(client), `${index}@${version}`);
328
327
  }
329
328
  return { versionsByIndex, rostersByIndex, indexDigestsByIndex };
330
329
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/xema",
3
- "version": "0.35.0",
3
+ "version": "0.36.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/xema-dev/xema-cli.git",
@@ -92,6 +92,6 @@
92
92
  "typecheck": "tsc --noEmit"
93
93
  },
94
94
  "xemaRelease": {
95
- "sourceDigest": "sha256:5a8392acd12bf89ba47fdff3d9cbb4ec49b8194b218af9ebbfaea8d6ce16114f"
95
+ "sourceDigest": "sha256:ddb945be16ae0e12c4ce9bd6fbb8b22dc9186a1bc6d927b2243fa762a600caa7"
96
96
  }
97
97
  }