@xemahq/xema 0.31.0 → 0.31.2
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.
- package/dist/edition/verify-image-evidence.bundle.provenance.json +36 -36
- package/edition/README.md +1 -1
- package/edition/build-runtime-image-source-index.mjs +7 -8
- package/edition/dist-check.mjs +20 -11
- package/edition/lib.mjs +12 -2
- package/edition/resolve-images.mjs +95 -17
- package/package.json +2 -2
|
@@ -2203,211 +2203,211 @@
|
|
|
2203
2203
|
},
|
|
2204
2204
|
{
|
|
2205
2205
|
"package": "@xemahq/xema",
|
|
2206
|
-
"version": "0.31.
|
|
2206
|
+
"version": "0.31.2",
|
|
2207
2207
|
"path": "edition/adapter-host-versions.mjs",
|
|
2208
2208
|
"sha256": "sha256:1b7ebd3592f4da1225fba74aaba912e7d85fbceeb1626f7dcdac83491cbb4d69"
|
|
2209
2209
|
},
|
|
2210
2210
|
{
|
|
2211
2211
|
"package": "@xemahq/xema",
|
|
2212
|
-
"version": "0.31.
|
|
2212
|
+
"version": "0.31.2",
|
|
2213
2213
|
"path": "edition/authorization-base.mjs",
|
|
2214
2214
|
"sha256": "sha256:bbeac7ff01376cb89ed2140526d4795d8e559b3f01612b404a701f19aaa24c6a"
|
|
2215
2215
|
},
|
|
2216
2216
|
{
|
|
2217
2217
|
"package": "@xemahq/xema",
|
|
2218
|
-
"version": "0.31.
|
|
2218
|
+
"version": "0.31.2",
|
|
2219
2219
|
"path": "edition/connector-source-authority.mjs",
|
|
2220
2220
|
"sha256": "sha256:ea94475f4324737673accd7de1303c44db1cbc4dac61a865a06cd83abe310164"
|
|
2221
2221
|
},
|
|
2222
2222
|
{
|
|
2223
2223
|
"package": "@xemahq/xema",
|
|
2224
|
-
"version": "0.31.
|
|
2224
|
+
"version": "0.31.2",
|
|
2225
2225
|
"path": "edition/distribution-paths.mjs",
|
|
2226
2226
|
"sha256": "sha256:d78a5c8405bc6c25d36fcec61b0030e1fdacac7d528e698adb96f906f4b70279"
|
|
2227
2227
|
},
|
|
2228
2228
|
{
|
|
2229
2229
|
"package": "@xemahq/xema",
|
|
2230
|
-
"version": "0.31.
|
|
2230
|
+
"version": "0.31.2",
|
|
2231
2231
|
"path": "edition/edition-artifact.mjs",
|
|
2232
2232
|
"sha256": "sha256:161f522eb39e3db705bc709f8512988dd3e6752851d972521354eeccffd8075d"
|
|
2233
2233
|
},
|
|
2234
2234
|
{
|
|
2235
2235
|
"package": "@xemahq/xema",
|
|
2236
|
-
"version": "0.31.
|
|
2236
|
+
"version": "0.31.2",
|
|
2237
2237
|
"path": "edition/edition-channel.mjs",
|
|
2238
2238
|
"sha256": "sha256:3c0c1564dc50be133cad500452d953353aa5beb703142c05a17bbce8175ba9f3"
|
|
2239
2239
|
},
|
|
2240
2240
|
{
|
|
2241
2241
|
"package": "@xemahq/xema",
|
|
2242
|
-
"version": "0.31.
|
|
2242
|
+
"version": "0.31.2",
|
|
2243
2243
|
"path": "edition/edition-chart-set.mjs",
|
|
2244
2244
|
"sha256": "sha256:fbda500315d45e35eb974f4701bbf36729c3b642a5d735bc1b07085c91d25b23"
|
|
2245
2245
|
},
|
|
2246
2246
|
{
|
|
2247
2247
|
"package": "@xemahq/xema",
|
|
2248
|
-
"version": "0.31.
|
|
2248
|
+
"version": "0.31.2",
|
|
2249
2249
|
"path": "edition/edition-config.mjs",
|
|
2250
2250
|
"sha256": "sha256:e3997bd9a0082e02d01760868b2a4f41ed3081e904126b30fdf86e7938dc6137"
|
|
2251
2251
|
},
|
|
2252
2252
|
{
|
|
2253
2253
|
"package": "@xemahq/xema",
|
|
2254
|
-
"version": "0.31.
|
|
2254
|
+
"version": "0.31.2",
|
|
2255
2255
|
"path": "edition/edition-constants.mjs",
|
|
2256
2256
|
"sha256": "sha256:71ae51028847ab3430ffec9b229b0516a7705b75a6de1fcfa665f5e1abf8e9bb"
|
|
2257
2257
|
},
|
|
2258
2258
|
{
|
|
2259
2259
|
"package": "@xemahq/xema",
|
|
2260
|
-
"version": "0.31.
|
|
2260
|
+
"version": "0.31.2",
|
|
2261
2261
|
"path": "edition/edition-contract-parse.mjs",
|
|
2262
2262
|
"sha256": "sha256:c575e96b70bda82899931eb0b18567988e2e13e664fa498bcbef96b571dcabb4"
|
|
2263
2263
|
},
|
|
2264
2264
|
{
|
|
2265
2265
|
"package": "@xemahq/xema",
|
|
2266
|
-
"version": "0.31.
|
|
2266
|
+
"version": "0.31.2",
|
|
2267
2267
|
"path": "edition/edition-contract.json",
|
|
2268
2268
|
"sha256": "sha256:aa1a05f1728813a7bdb1e02d9305e9adf641d695e6767305210c67a1d81b38a7"
|
|
2269
2269
|
},
|
|
2270
2270
|
{
|
|
2271
2271
|
"package": "@xemahq/xema",
|
|
2272
|
-
"version": "0.31.
|
|
2272
|
+
"version": "0.31.2",
|
|
2273
2273
|
"path": "edition/edition-protocol.mjs",
|
|
2274
2274
|
"sha256": "sha256:2940a0ee8662970722aa2618a1635f8d5b4f5e54b85f09667f71ccf7c2c81b03"
|
|
2275
2275
|
},
|
|
2276
2276
|
{
|
|
2277
2277
|
"package": "@xemahq/xema",
|
|
2278
|
-
"version": "0.31.
|
|
2278
|
+
"version": "0.31.2",
|
|
2279
2279
|
"path": "edition/edition-workspace.mjs",
|
|
2280
2280
|
"sha256": "sha256:f7267e93fd7dc07cf65fb8cac2c4439d28a72c1e0acbdeca1648c6859440eb32"
|
|
2281
2281
|
},
|
|
2282
2282
|
{
|
|
2283
2283
|
"package": "@xemahq/xema",
|
|
2284
|
-
"version": "0.31.
|
|
2284
|
+
"version": "0.31.2",
|
|
2285
2285
|
"path": "edition/evidence-checkout.mjs",
|
|
2286
2286
|
"sha256": "sha256:31fb669769b31de4c6f2b2501bb96959548172ef166e7568edbbfed7f5079a11"
|
|
2287
2287
|
},
|
|
2288
2288
|
{
|
|
2289
2289
|
"package": "@xemahq/xema",
|
|
2290
|
-
"version": "0.31.
|
|
2290
|
+
"version": "0.31.2",
|
|
2291
2291
|
"path": "edition/evidence-grammars.mjs",
|
|
2292
2292
|
"sha256": "sha256:4dae22b61ade99219a482b971c9780d68a3d37d021e39cdfe860b245364b8b9f"
|
|
2293
2293
|
},
|
|
2294
2294
|
{
|
|
2295
2295
|
"package": "@xemahq/xema",
|
|
2296
|
-
"version": "0.31.
|
|
2296
|
+
"version": "0.31.2",
|
|
2297
2297
|
"path": "edition/evidence-trust-pin.mjs",
|
|
2298
2298
|
"sha256": "sha256:b9dd5c01903394436530783614efb0cd357d982ed2befd844a39328479773cbc"
|
|
2299
2299
|
},
|
|
2300
2300
|
{
|
|
2301
2301
|
"package": "@xemahq/xema",
|
|
2302
|
-
"version": "0.31.
|
|
2302
|
+
"version": "0.31.2",
|
|
2303
2303
|
"path": "edition/image-delivery-entitlement-descriptor.mjs",
|
|
2304
2304
|
"sha256": "sha256:4726b66116f01bf2523fafe2b7a356591eca8fb5ca6bd8b154dd4821873e921b"
|
|
2305
2305
|
},
|
|
2306
2306
|
{
|
|
2307
2307
|
"package": "@xemahq/xema",
|
|
2308
|
-
"version": "0.31.
|
|
2308
|
+
"version": "0.31.2",
|
|
2309
2309
|
"path": "edition/image-evidence-replay-state.mjs",
|
|
2310
2310
|
"sha256": "sha256:eba0cf1d38af0ab2f00c5099fa8bc2edc543136ce92f895544d4d284b3d6af0f"
|
|
2311
2311
|
},
|
|
2312
2312
|
{
|
|
2313
2313
|
"package": "@xemahq/xema",
|
|
2314
|
-
"version": "0.31.
|
|
2314
|
+
"version": "0.31.2",
|
|
2315
2315
|
"path": "edition/image-evidence.mjs",
|
|
2316
2316
|
"sha256": "sha256:3192b411d52f8ce7e32d3f8cba977692ce021a00ad1b7f72248a747ef3a8d45c"
|
|
2317
2317
|
},
|
|
2318
2318
|
{
|
|
2319
2319
|
"package": "@xemahq/xema",
|
|
2320
|
-
"version": "0.31.
|
|
2320
|
+
"version": "0.31.2",
|
|
2321
2321
|
"path": "edition/kernel-capability-domain.mjs",
|
|
2322
2322
|
"sha256": "sha256:3ecf887dd8d399e91a8285f6f115f6e418fb59bbf3f004539fe65ec667219356"
|
|
2323
2323
|
},
|
|
2324
2324
|
{
|
|
2325
2325
|
"package": "@xemahq/xema",
|
|
2326
|
-
"version": "0.31.
|
|
2326
|
+
"version": "0.31.2",
|
|
2327
2327
|
"path": "edition/kernel-contract-authority.mjs",
|
|
2328
2328
|
"sha256": "sha256:20abdde62a7b037c01ea9bbe1ff1e6094e6b0efd0add2f656f1938a04409bf82"
|
|
2329
2329
|
},
|
|
2330
2330
|
{
|
|
2331
2331
|
"package": "@xemahq/xema",
|
|
2332
|
-
"version": "0.31.
|
|
2332
|
+
"version": "0.31.2",
|
|
2333
2333
|
"path": "edition/lib.mjs",
|
|
2334
|
-
"sha256": "sha256:
|
|
2334
|
+
"sha256": "sha256:f7da6a34588354e12c44196287e130b9098190fbde57b38c3a87dfeafee5cb7d"
|
|
2335
2335
|
},
|
|
2336
2336
|
{
|
|
2337
2337
|
"package": "@xemahq/xema",
|
|
2338
|
-
"version": "0.31.
|
|
2338
|
+
"version": "0.31.2",
|
|
2339
2339
|
"path": "edition/no-follow-file.mjs",
|
|
2340
2340
|
"sha256": "sha256:c17bdf5e441f3c079aa06d4b48bbed05cad087855b9ad2a5e6dc43d5ee2b17c3"
|
|
2341
2341
|
},
|
|
2342
2342
|
{
|
|
2343
2343
|
"package": "@xemahq/xema",
|
|
2344
|
-
"version": "0.31.
|
|
2344
|
+
"version": "0.31.2",
|
|
2345
2345
|
"path": "edition/operation-requirements.mjs",
|
|
2346
2346
|
"sha256": "sha256:ffe6fdc9da6b2974270fc86c11be0c41d0bc6d85c8e3c137d3c3bc00a72fc4f6"
|
|
2347
2347
|
},
|
|
2348
2348
|
{
|
|
2349
2349
|
"package": "@xemahq/xema",
|
|
2350
|
-
"version": "0.31.
|
|
2350
|
+
"version": "0.31.2",
|
|
2351
2351
|
"path": "edition/pin-source.mjs",
|
|
2352
2352
|
"sha256": "sha256:4e64d25b7aacec344253d1963f419f946998f36e8c269eea58b8c848e0f35e52"
|
|
2353
2353
|
},
|
|
2354
2354
|
{
|
|
2355
2355
|
"package": "@xemahq/xema",
|
|
2356
|
-
"version": "0.31.
|
|
2356
|
+
"version": "0.31.2",
|
|
2357
2357
|
"path": "edition/source-authority.mjs",
|
|
2358
2358
|
"sha256": "sha256:2351d47a32ee865720a675f1ecd336b00cdce4aa34713219a1aa23920ac7b60f"
|
|
2359
2359
|
},
|
|
2360
2360
|
{
|
|
2361
2361
|
"package": "@xemahq/xema",
|
|
2362
|
-
"version": "0.31.
|
|
2362
|
+
"version": "0.31.2",
|
|
2363
2363
|
"path": "edition/strict-json.mjs",
|
|
2364
2364
|
"sha256": "sha256:f95778396df7f38b086f55d2ec4f3b6644a8aeff2b32282a62829145fb544562"
|
|
2365
2365
|
},
|
|
2366
2366
|
{
|
|
2367
2367
|
"package": "@xemahq/xema",
|
|
2368
|
-
"version": "0.31.
|
|
2368
|
+
"version": "0.31.2",
|
|
2369
2369
|
"path": "edition/string-order.mjs",
|
|
2370
2370
|
"sha256": "sha256:b3210cd273e4b2e01fb8b1a91e28734cd211d4010c080d0ce95f5e5ff631cffb"
|
|
2371
2371
|
},
|
|
2372
2372
|
{
|
|
2373
2373
|
"package": "@xemahq/xema",
|
|
2374
|
-
"version": "0.31.
|
|
2374
|
+
"version": "0.31.2",
|
|
2375
2375
|
"path": "edition/trusted-executable.mjs",
|
|
2376
2376
|
"sha256": "sha256:37d46cdbc999ddd55d4ea8aeed4850ddd1efde89ed7b532f5a2ddec87105d796"
|
|
2377
2377
|
},
|
|
2378
2378
|
{
|
|
2379
2379
|
"package": "@xemahq/xema",
|
|
2380
|
-
"version": "0.31.
|
|
2380
|
+
"version": "0.31.2",
|
|
2381
2381
|
"path": "edition/verifier-binding.mjs",
|
|
2382
2382
|
"sha256": "sha256:80732658617f5255258c538eeb2383331ec8553b44b58d552b567845a7b916aa"
|
|
2383
2383
|
},
|
|
2384
2384
|
{
|
|
2385
2385
|
"package": "@xemahq/xema",
|
|
2386
|
-
"version": "0.31.
|
|
2386
|
+
"version": "0.31.2",
|
|
2387
2387
|
"path": "edition/verifier-files.mjs",
|
|
2388
2388
|
"sha256": "sha256:cdd14a20a63f0f194a8abb55680a5a7e3ced1f09f8b210a90d349e655f6de0c0"
|
|
2389
2389
|
},
|
|
2390
2390
|
{
|
|
2391
2391
|
"package": "@xemahq/xema",
|
|
2392
|
-
"version": "0.31.
|
|
2392
|
+
"version": "0.31.2",
|
|
2393
2393
|
"path": "edition/verifier-provenance.mjs",
|
|
2394
2394
|
"sha256": "sha256:3e2fb8e07cf1f66b8ad6c7ac2555fe3af64ec7abeb07cecbaf1939a18c2b3663"
|
|
2395
2395
|
},
|
|
2396
2396
|
{
|
|
2397
2397
|
"package": "@xemahq/xema",
|
|
2398
|
-
"version": "0.31.
|
|
2398
|
+
"version": "0.31.2",
|
|
2399
2399
|
"path": "edition/verify-image-evidence.mjs",
|
|
2400
2400
|
"sha256": "sha256:62f83f8bb835f360535402d12657156d2c9d6e651b426c2b30a04a2dc2f8d3e8"
|
|
2401
2401
|
},
|
|
2402
2402
|
{
|
|
2403
2403
|
"package": "@xemahq/xema",
|
|
2404
|
-
"version": "0.31.
|
|
2404
|
+
"version": "0.31.2",
|
|
2405
2405
|
"path": "edition/workspace-sections.mjs",
|
|
2406
2406
|
"sha256": "sha256:058c849767434e9ba911d9310092bede42e3ef959c75bbd35ff8879dc21ce3ff"
|
|
2407
2407
|
},
|
|
2408
2408
|
{
|
|
2409
2409
|
"package": "@xemahq/xema",
|
|
2410
|
-
"version": "0.31.
|
|
2410
|
+
"version": "0.31.2",
|
|
2411
2411
|
"path": "scripts/build-evidence-verifier.mjs",
|
|
2412
2412
|
"sha256": "sha256:5a688d20c47dc88aff37aa0c6cc02daf2c370a5bc610fef8446ce7be222d4c0b"
|
|
2413
2413
|
},
|
package/edition/README.md
CHANGED
|
@@ -98,7 +98,7 @@ The edition library builds, validates and verifies evidence statements; it never
|
|
|
98
98
|
The CLI is coupled to the kernel's edition protocol, not to the kernel package. `@xemahq/contracts` exports the protocol identity as data (`dist/edition-protocol/edition-protocol.json`: `{contentDigest, provisional, version}`). This CLI supports exactly protocol v5 and REFUSES an identity with `provisional: true`; every loader that executes the kernel, `xema edition check` first, and the evidence verifier compare only that identity and refuse an unsupported one, naming the supported and the declared versions. A protocol change needs a CLI release first; only then does the data root repin its kernel authority.
|
|
99
99
|
|
|
100
100
|
- `xema edition evidence statement entitlement stage` writes entitlement predicate v2 (`lockDigest`, `catalogueDigest`, read from the edition's committed locks), so it takes `--editions-root` besides `--data-root` and `--kernel`.
|
|
101
|
-
- The runtime image source index is v2 and carries operator-stated `producerWorkflowPins` (the workflow commit a producer certificate must be signed from, per repository). `xema edition index runtime-image-source [--producer-workflow-pin <owner/repo>=<40-hex>]...` preserves the committed pins exactly; each flag sets one repository's pin (repeatable; a repeated or non-GitHub `owner/repo` is refused; only `--trusted-write` writes an index, so the flag with any other mode, `--check-sources` included, is refused); a bootstrap index with none writes `[]`. A v1 index is
|
|
101
|
+
- The runtime image source index is v2 and carries operator-stated `producerWorkflowPins` (the workflow commit a producer certificate must be signed from, per repository). `xema edition index runtime-image-source [--producer-workflow-pin <owner/repo>=<40-hex>]...` preserves the committed pins exactly; each flag sets one repository's pin (repeatable; a repeated or non-GitHub `owner/repo` is refused; only `--trusted-write` writes an index, so the flag with any other mode, `--check-sources` included, is refused); a bootstrap index with none writes `[]`. A v1 index is refused, never migrated: delete it and bootstrap a new one with `--kernel-commit`.
|
|
102
102
|
|
|
103
103
|
## Customer editions
|
|
104
104
|
|
|
@@ -204,9 +204,7 @@ function assertVendoredSourcesResolve(crossRepoBuildInputs, resolveIdentity) {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
const LEGACY_INDEX_SCHEMA_VERSION = 1;
|
|
208
207
|
const CURRENT_INDEX_SCHEMA_VERSION = 2;
|
|
209
|
-
const KNOWN_INDEX_SCHEMA_VERSIONS = Object.freeze([LEGACY_INDEX_SCHEMA_VERSION, CURRENT_INDEX_SCHEMA_VERSION]);
|
|
210
208
|
|
|
211
209
|
/**
|
|
212
210
|
* The kernel-contract authority for a pin regeneration.
|
|
@@ -255,9 +253,9 @@ const KNOWN_INDEX_SCHEMA_VERSIONS = Object.freeze([LEGACY_INDEX_SCHEMA_VERSION,
|
|
|
255
253
|
* HEAD must equal it. Stating a commit when a committed authority exists is
|
|
256
254
|
* refused: it would be read by nobody.
|
|
257
255
|
*
|
|
258
|
-
* A committed index of schemaVersion
|
|
259
|
-
*
|
|
260
|
-
*
|
|
256
|
+
* A committed index of any schemaVersion but the current one is refused by name,
|
|
257
|
+
* never migrated: a schemaVersion 1 index is re-indexed by deleting it and
|
|
258
|
+
* running bootstrap. Any other
|
|
261
259
|
* schemaVersion is refused by name, never read as one of these.
|
|
262
260
|
*/
|
|
263
261
|
async function resolveContractAuthority(schemas, kernelRoot, kernelCommit) {
|
|
@@ -265,13 +263,14 @@ async function resolveContractAuthority(schemas, kernelRoot, kernelCommit) {
|
|
|
265
263
|
const committed = existsSync(runtimeImageSourceIndexPath())
|
|
266
264
|
? readJson(runtimeImageSourceIndexPath())
|
|
267
265
|
: undefined;
|
|
268
|
-
if (committed !== undefined &&
|
|
266
|
+
if (committed !== undefined && committed.schemaVersion !== CURRENT_INDEX_SCHEMA_VERSION) {
|
|
269
267
|
throw new Error(
|
|
270
268
|
`${runtimeImageSourceIndexPath()} has schemaVersion ${JSON.stringify(committed.schemaVersion)}; ` +
|
|
271
|
-
`this command reads ${
|
|
269
|
+
`this command reads only schemaVersion ${CURRENT_INDEX_SCHEMA_VERSION} and does not migrate older indexes: ` +
|
|
270
|
+
`delete the index and re-run with ${KERNEL_COMMIT_FLAG} <40-hex> to bootstrap a new one`,
|
|
272
271
|
);
|
|
273
272
|
}
|
|
274
|
-
if (committed === undefined ||
|
|
273
|
+
if (committed === undefined || !committed.contractAuthority) {
|
|
275
274
|
return buildTrustedKernelContractAuthority({
|
|
276
275
|
...(repositoryDirectory === undefined ? {} : { repositoryDirectory }),
|
|
277
276
|
schemas,
|
package/edition/dist-check.mjs
CHANGED
|
@@ -52,7 +52,9 @@ import { checkEvidenceTrustPolicy } from './evidence-trust-policy.mjs';
|
|
|
52
52
|
import {
|
|
53
53
|
compareIndexEntries,
|
|
54
54
|
comparableDistributionLock,
|
|
55
|
+
isUnsealedDistributionLock,
|
|
55
56
|
loadKernelDistributionSchemas,
|
|
57
|
+
parseResolvedDistributionLock,
|
|
56
58
|
serializeJson,
|
|
57
59
|
validateImmutableBiomeIndex,
|
|
58
60
|
validateImmutableDistributionLock,
|
|
@@ -263,13 +265,15 @@ function imageStructure(lock) {
|
|
|
263
265
|
* subjects as stale on a clean tree and send the reader to re-resolve, which
|
|
264
266
|
* is the operation that destroys the seal.
|
|
265
267
|
*/
|
|
266
|
-
async function checkImagesLock(id, checkSourceEvidence) {
|
|
268
|
+
export async function checkImagesLock(id, checkSourceEvidence) {
|
|
267
269
|
const imageLockPath = join(editionsRoot(), id, 'images.lock.json');
|
|
268
270
|
try {
|
|
269
271
|
const schemas = await loadKernelDistributionSchemas();
|
|
270
|
-
// A pure READ of the committed lock: the
|
|
272
|
+
// A pure READ of the committed lock: the shape-dispatching reader (unsealed
|
|
273
|
+
// on develop, sealed v5 otherwise), never the writer.
|
|
271
274
|
const distributionLock = validateImmutableDistributionLock(
|
|
272
|
-
|
|
275
|
+
parseResolvedDistributionLock(
|
|
276
|
+
schemas,
|
|
273
277
|
JSON.parse(
|
|
274
278
|
readFileSync(
|
|
275
279
|
join(editionsRoot(), id, 'distribution.lock.json'),
|
|
@@ -851,12 +855,15 @@ function checkConfinementScope(ids) {
|
|
|
851
855
|
* digests, and a mismatch is refused naming the biome. The kernel cannot do
|
|
852
856
|
* this ("sealed" is only a field). Returns true on green.
|
|
853
857
|
*/
|
|
854
|
-
async function checkBiomeContentHashes(id) {
|
|
858
|
+
export async function checkBiomeContentHashes(id) {
|
|
855
859
|
try {
|
|
856
860
|
const schemas = await loadKernelDistributionSchemas();
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
|
|
861
|
+
const rawLock = JSON.parse(readFileSync(join(editionsRoot(), id, 'distribution.lock.json'), 'utf8'));
|
|
862
|
+
if (isUnsealedDistributionLock(rawLock)) {
|
|
863
|
+
console.log(`[dist:check] ${id}: unsealed lock, no biome content hashes to verify until sealed.`);
|
|
864
|
+
return true;
|
|
865
|
+
}
|
|
866
|
+
const lock = schemas.parseDistributionLock(rawLock);
|
|
860
867
|
const imageLock = schemas.parseImageLock(
|
|
861
868
|
JSON.parse(readFileSync(join(editionsRoot(), id, 'images.lock.json'), 'utf8')),
|
|
862
869
|
);
|
|
@@ -981,7 +988,9 @@ async function main() {
|
|
|
981
988
|
console.log('[dist:check] all distributions green.');
|
|
982
989
|
}
|
|
983
990
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
991
|
+
if (isEntryModule(import.meta.url)) {
|
|
992
|
+
main().catch((err) => {
|
|
993
|
+
console.error(`[dist:check] ${err.message}`);
|
|
994
|
+
process.exit(1);
|
|
995
|
+
});
|
|
996
|
+
}
|
package/edition/lib.mjs
CHANGED
|
@@ -2789,6 +2789,16 @@ export function validateImmutableBiomeIndex(index) {
|
|
|
2789
2789
|
return index;
|
|
2790
2790
|
}
|
|
2791
2791
|
|
|
2792
|
+
/**
|
|
2793
|
+
* Whether a raw distribution lock DECLARES the unsealed shape (carries
|
|
2794
|
+
* `unsealedSchema`). Dispatch is on the declared shape only, never on a parse
|
|
2795
|
+
* failure: a sealed (schemaVersion 5) lock that is incomplete stays sealed and
|
|
2796
|
+
* is refused by the sealed parsers.
|
|
2797
|
+
*/
|
|
2798
|
+
export function isUnsealedDistributionLock(raw) {
|
|
2799
|
+
return raw !== null && typeof raw === 'object' && 'unsealedSchema' in raw;
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2792
2802
|
/**
|
|
2793
2803
|
* The distribution lock as the resolve pipeline reads it: the UNSEALED
|
|
2794
2804
|
* document a resolve just wrote, or the SEALED v5 lock a prior seal committed.
|
|
@@ -2797,7 +2807,7 @@ export function validateImmutableBiomeIndex(index) {
|
|
|
2797
2807
|
* A pre-v5 lock is refused by the kernel (`unsupported-schema-version`).
|
|
2798
2808
|
*/
|
|
2799
2809
|
export function parseResolvedDistributionLock(schemas, raw) {
|
|
2800
|
-
return raw
|
|
2810
|
+
return isUnsealedDistributionLock(raw)
|
|
2801
2811
|
? schemas.parseUnsealedDistributionLock(raw)
|
|
2802
2812
|
: schemas.parseDistributionLockForReading(raw);
|
|
2803
2813
|
}
|
|
@@ -2812,7 +2822,7 @@ export function parseResolvedDistributionLock(schemas, raw) {
|
|
|
2812
2822
|
*/
|
|
2813
2823
|
export function comparableDistributionLock(schemas, raw) {
|
|
2814
2824
|
const unsealed = schemas.parseUnsealedDistributionLock(
|
|
2815
|
-
raw
|
|
2825
|
+
isUnsealedDistributionLock(raw)
|
|
2816
2826
|
? raw
|
|
2817
2827
|
: schemas.unsealedProjection(schemas.parseDistributionLock(raw)),
|
|
2818
2828
|
);
|
|
@@ -870,6 +870,63 @@ export function editionSourceIds(lock) {
|
|
|
870
870
|
return { get: (repo) => ids.get(repo) ?? firstPartySourceId(repo) };
|
|
871
871
|
}
|
|
872
872
|
|
|
873
|
+
/**
|
|
874
|
+
* A composed-process declaration the build cannot be read from. Named so a
|
|
875
|
+
* caller can tell "this image's inputs are unknown" from any other refusal:
|
|
876
|
+
* the carried set is evidence, and with none there is no owner to derive.
|
|
877
|
+
*/
|
|
878
|
+
export class ComposedProcessInputsError extends Error {
|
|
879
|
+
constructor(message) {
|
|
880
|
+
super(message);
|
|
881
|
+
this.name = 'ComposedProcessInputsError';
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Which of a repository's biome services the composed image CARRIES, read from
|
|
887
|
+
* the composed build's own inputs at the sealed commit.
|
|
888
|
+
*
|
|
889
|
+
* `image-build-inputs.json` lists the member package directories the image is
|
|
890
|
+
* built from (its hash is the subject's `sourceManifestHash`). A service is
|
|
891
|
+
* carried when its manifest-declared source directory (`subjectServicePath`,
|
|
892
|
+
* the `components[].artifact.path` mapping) is one of them. Returns one row
|
|
893
|
+
* per biome: the service ids carried and the ones not.
|
|
894
|
+
*/
|
|
895
|
+
function composedProcessCarriage(structure, enums, repo, sourceCommit, locate) {
|
|
896
|
+
const inputsPath = `${COMPOSED_PROCESS_IMAGE_PATH}/${COMPOSED_PROCESS_DECLARATION_FILE}`;
|
|
897
|
+
const { dir } = locate(repo);
|
|
898
|
+
let members;
|
|
899
|
+
try {
|
|
900
|
+
members = readGitJsonAtCommit(dir, inputsPath, sourceCommit)?.workspacePackages;
|
|
901
|
+
} catch (cause) {
|
|
902
|
+
throw new ComposedProcessInputsError(
|
|
903
|
+
`composed-process inputs "${inputsPath}" of "${repo}" are unreadable at ${sourceCommit} ` +
|
|
904
|
+
`(${cause.message}) — the biomes the image carries cannot be derived`,
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
if (!Array.isArray(members) || members.some((member) => typeof member !== 'string')) {
|
|
908
|
+
throw new ComposedProcessInputsError(
|
|
909
|
+
`composed-process inputs "${inputsPath}" of "${repo}" at ${sourceCommit} declare no ` +
|
|
910
|
+
'"workspacePackages" array of directories — the biomes the image carries cannot be derived',
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
const carried = new Set(members);
|
|
914
|
+
const byBiome = new Map();
|
|
915
|
+
for (const subject of structure.subjects) {
|
|
916
|
+
if (subject.kind !== enums.RuntimeImageSubjectKind.Service || subject.repo !== repo) {continue;}
|
|
917
|
+
const servicePath = subjectServicePath(subject, sourceCommit, locate);
|
|
918
|
+
for (const owner of subject.owners) {
|
|
919
|
+
if (owner.kind !== enums.RuntimeImageOwnerKind.Biome) {continue;}
|
|
920
|
+
const row = byBiome.get(owner.biomeId) ?? { biomeId: owner.biomeId, carried: [], uncarried: [] };
|
|
921
|
+
(carried.has(servicePath) ? row.carried : row.uncarried).push(subject.id);
|
|
922
|
+
byBiome.set(owner.biomeId, row);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
return [...byBiome.values()]
|
|
926
|
+
.map((row) => ({ ...row, carried: row.carried.sort(compareStrings), uncarried: row.uncarried.sort(compareStrings) }))
|
|
927
|
+
.sort((a, b) => compareStrings(a.biomeId, b.biomeId));
|
|
928
|
+
}
|
|
929
|
+
|
|
873
930
|
/**
|
|
874
931
|
* Read each repository's composed-process DECLARATION at the commit the
|
|
875
932
|
* edition builds its services from. Only repositories that contribute a
|
|
@@ -920,6 +977,7 @@ export function readComposedProcessDeclarations(
|
|
|
920
977
|
repo,
|
|
921
978
|
sourceId,
|
|
922
979
|
sourceCommit,
|
|
980
|
+
carriage: composedProcessCarriage(structure, enums, repo, sourceCommit, locate),
|
|
923
981
|
path: `${repoRelative}/${COMPOSED_PROCESS_IMAGE_PATH}`,
|
|
924
982
|
sourceManifestPath: `${repoRelative}/${declarationPath}`,
|
|
925
983
|
sourceManifestHash: exactSourceManifestHash(dir, declarationPath, sourceCommit),
|
|
@@ -933,10 +991,17 @@ export function readComposedProcessDeclarations(
|
|
|
933
991
|
* structure. Pure over its inputs, so the structural check and the source
|
|
934
992
|
* resolve derive the same subject from the same declarations.
|
|
935
993
|
*
|
|
936
|
-
* Owners are the biomes
|
|
937
|
-
*
|
|
994
|
+
* Owners are the biomes the image CARRIES, derived from the composed build's
|
|
995
|
+
* inputs at the sealed commit (`declaration.carriage`): the biomes all of whose
|
|
996
|
+
* services are members, never every biome with a service in the repository.
|
|
938
997
|
*/
|
|
939
|
-
export function withComposedProcessSubjects(
|
|
998
|
+
export function withComposedProcessSubjects(
|
|
999
|
+
structure,
|
|
1000
|
+
declarations,
|
|
1001
|
+
enums,
|
|
1002
|
+
requiredPlatforms,
|
|
1003
|
+
{ onNotice = (message) => console.warn(`[dist:images] ${message}`) } = {},
|
|
1004
|
+
) {
|
|
940
1005
|
if (declarations.length === 0) {return structure;}
|
|
941
1006
|
const subjects = new Map(structure.subjects.map((subject) => [subjectKey(subject), subject]));
|
|
942
1007
|
for (const declaration of declarations) {
|
|
@@ -944,20 +1009,32 @@ export function withComposedProcessSubjects(structure, declarations, enums, requ
|
|
|
944
1009
|
(subject) =>
|
|
945
1010
|
subject.kind === enums.RuntimeImageSubjectKind.Service && subject.repo === declaration.repo,
|
|
946
1011
|
);
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
];
|
|
1012
|
+
if (!Array.isArray(declaration.carriage)) {
|
|
1013
|
+
throw new ComposedProcessInputsError(
|
|
1014
|
+
`composed-process declaration for "${declaration.repo}" carries no evidence of the ` +
|
|
1015
|
+
'biomes the image carries — refusing to guess its owners',
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
// Owners are the biomes ALL of whose services the image carries. A biome
|
|
1019
|
+
// with only some carried deploys dedicated, so it is no owner (and is
|
|
1020
|
+
// named); a biome with none carried is simply not one.
|
|
1021
|
+
const biomeOwners = [];
|
|
1022
|
+
for (const row of declaration.carriage) {
|
|
1023
|
+
if (row.carried.length === 0) {continue;}
|
|
1024
|
+
if (row.uncarried.length > 0) {
|
|
1025
|
+
onNotice(
|
|
1026
|
+
`composed-process "${declaration.repo}": biome "${row.biomeId}" is only partly carried ` +
|
|
1027
|
+
`(carried: ${row.carried.join(', ')}; not carried: ${row.uncarried.join(', ')}) — ` +
|
|
1028
|
+
'it is not an owner and deploys dedicated',
|
|
1029
|
+
);
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
biomeOwners.push({ kind: enums.RuntimeImageOwnerKind.Biome, biomeId: row.biomeId });
|
|
1033
|
+
}
|
|
957
1034
|
if (biomeOwners.length === 0) {
|
|
958
1035
|
throw new Error(
|
|
959
|
-
`composed-process declaration for "${declaration.repo}"
|
|
960
|
-
'
|
|
1036
|
+
`composed-process declaration for "${declaration.repo}" carries no biome's services in ` +
|
|
1037
|
+
'this edition — a composed image carries services, so it has no owner',
|
|
961
1038
|
);
|
|
962
1039
|
}
|
|
963
1040
|
for (const subject of services) {
|
|
@@ -1001,7 +1078,7 @@ export function withComposedProcessSubjects(structure, declarations, enums, requ
|
|
|
1001
1078
|
sourceManifestHash: declaration.sourceManifestHash,
|
|
1002
1079
|
sourceManifestPath: declaration.sourceManifestPath,
|
|
1003
1080
|
requiredPlatforms,
|
|
1004
|
-
owners: biomeOwners
|
|
1081
|
+
owners: biomeOwners,
|
|
1005
1082
|
});
|
|
1006
1083
|
}
|
|
1007
1084
|
return {
|
|
@@ -1023,7 +1100,7 @@ export function resolveComposedProcessStructure(
|
|
|
1023
1100
|
structure,
|
|
1024
1101
|
enums,
|
|
1025
1102
|
requiredPlatforms,
|
|
1026
|
-
{ locate } = {},
|
|
1103
|
+
{ locate, onNotice } = {},
|
|
1027
1104
|
) {
|
|
1028
1105
|
return withComposedProcessSubjects(
|
|
1029
1106
|
structure,
|
|
@@ -1036,6 +1113,7 @@ export function resolveComposedProcessStructure(
|
|
|
1036
1113
|
),
|
|
1037
1114
|
enums,
|
|
1038
1115
|
requiredPlatforms,
|
|
1116
|
+
onNotice === undefined ? undefined : { onNotice },
|
|
1039
1117
|
);
|
|
1040
1118
|
}
|
|
1041
1119
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/xema",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.2",
|
|
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:
|
|
95
|
+
"sourceDigest": "sha256:98d3df3b954a3e3149f8099e228a7649cbba3f0ed37fbfc59c2c1e3cc3a2acef"
|
|
96
96
|
}
|
|
97
97
|
}
|