@xemahq/xema 0.44.0 → 0.45.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.
- package/dist/edition/verify-image-evidence.bundle.mjs +926 -810
- package/dist/edition/verify-image-evidence.bundle.provenance.json +468 -456
- package/edition/README.md +1 -1
- package/edition/edition-protocol.mjs +5 -1
- package/edition/image-lock-service-rows.mjs +24 -0
- package/edition/resolve-customer-edition.mjs +2 -2
- package/package.json +3 -3
package/edition/README.md
CHANGED
|
@@ -142,7 +142,7 @@ The edition library builds, validates and verifies evidence statements; it never
|
|
|
142
142
|
|
|
143
143
|
## Kernel protocol and pins
|
|
144
144
|
|
|
145
|
-
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 protocols v9 to
|
|
145
|
+
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 protocols v9 to v16 and v19 to v20 (the versions the kernel declared and contracts published), each pinned to its digest and vendored (v10 to v20 grow the kernel source closure only; a data root whose pinned kernel speaks v8 stays on CLI 0.41.x, v5 on 0.33.x) 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.
|
|
146
146
|
|
|
147
147
|
A develop edition does not take the kernel's develop head blindly: `xema edition develop choose-kernel --kernel <package dir> [--kernel-pin <40-hex>] --out <file>` reads the declared protocol of each commit on the checkout's first-parent history (from source, unbuilt) and chooses the newest one this CLI supports. It writes `{chosenSha, headSha, held, reason}` (`reason`: `head-supported` | `head-ahead` | `explicit-pin`; `held` is `head-ahead`), and when held prints `kernel held at v<N> (<sha12>), head at v<M> (<sha12>): raise the CLI` (stdout only, never persisted). The head is the checkout's `refs/remotes/origin/develop` (a full-history checkout). An explicit pin wins but is still checked, and must be on that head's first-parent history (`not-on-develop` otherwise); when no commit is supported it refuses (`EditionProtocolMismatchError`, `no-supported-commit`; the walk ends at the first commit with no declaration file) and never falls back to the head; a declaration that exists but does not parse, at the head or any walked commit, is refused by name (`unparseable`), never skipped. `freeze-graph` applies the same check to `--kernel-sha`.
|
|
148
148
|
|
|
@@ -28,7 +28,7 @@ import { realpathSync } from 'node:fs';
|
|
|
28
28
|
|
|
29
29
|
import { readBoundedNoFollowFile } from './no-follow-file.mjs';
|
|
30
30
|
|
|
31
|
-
/** The edition protocols this library interprets: version -> content digest. v10..
|
|
31
|
+
/** The edition protocols this library interprets: version -> content digest. v10..v20 grow the kernel
|
|
32
32
|
* source closure only (entry subpaths and hashing unchanged), so one library speaks every row. */
|
|
33
33
|
export const SUPPORTED_EDITION_PROTOCOLS = Object.freeze([
|
|
34
34
|
Object.freeze({ version: 9, contentDigest: '7cd6d760e7e7caaec3634a08c739debbdeeeaac4f1bad6791246a12f4f248e37' }),
|
|
@@ -37,6 +37,10 @@ export const SUPPORTED_EDITION_PROTOCOLS = Object.freeze([
|
|
|
37
37
|
Object.freeze({ version: 12, contentDigest: 'cff51ea06b6ba7d95d02dcd6305b6a55061b428da48ae74dcbff8a5c8107ce41' }),
|
|
38
38
|
Object.freeze({ version: 13, contentDigest: '5f69fe73d1dea1650ef1757204a53ccd4030ade78bfa91959c2d01c937fc0e16' }),
|
|
39
39
|
Object.freeze({ version: 14, contentDigest: '403b6a491b5922df1a423ba8a2d6ae3d3900bb1caff4e8c0caa48de90a47eb9b' }),
|
|
40
|
+
Object.freeze({ version: 15, contentDigest: 'c66191703abfd9b532d8b6c15476bede2a5752af5bea5032e839fb9d6303a2d1' }),
|
|
41
|
+
Object.freeze({ version: 16, contentDigest: '2e65c280a399304ebb438e4e9829bcb4688f36a3c6a5e8b35b679cf69c689f55' }),
|
|
42
|
+
Object.freeze({ version: 19, contentDigest: '66dab3dcf18c3a587f073808cc91165cc513eabb237b35439ff6cfe2b312b127' }),
|
|
43
|
+
Object.freeze({ version: 20, contentDigest: '22c0e4ba6ee2771e91516ea78806117b5e3e60b76e085b9a9b98e993c1de79f8' }),
|
|
40
44
|
]);
|
|
41
45
|
|
|
42
46
|
/** Where a kernel package publishes its identity and its contract, package-relative. */
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// image-lock-service-rows — the one answer to "which image row serves this service or runtime component of this biome".
|
|
2
|
+
//
|
|
3
|
+
// A schemaVersion-4 images lock gives a service composed into a process NO subject of its own: it is a
|
|
4
|
+
// `members[]` entry (`{service, packageDir}`) of a `composed-process` subject whose `owners` are the member biomes.
|
|
5
|
+
// Every CLI read that asks whether a lock or catalogue carries the image of a biome's service goes through here, so
|
|
6
|
+
// no reader can miss the composed form.
|
|
7
|
+
|
|
8
|
+
/** Whether `subject` is owned by the biome `biomeId`. */
|
|
9
|
+
function isOwnedByBiome(subject, biomeId, enums) {
|
|
10
|
+
return subject.owners.some((owner) => owner.kind === enums.RuntimeImageOwnerKind.Biome && owner.biomeId === biomeId);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The subject carrying the image of `kind:id` for the biome `biomeId`, or undefined.
|
|
15
|
+
* A service is served by (a) a Service subject with that id owned by the biome, or (b) a subject owned by the biome
|
|
16
|
+
* whose `members[]` names the service. The biome's own `services` list supplies `id`, and contracts guarantees member
|
|
17
|
+
* service names are unique within a subject, so the owner check pairs the member with the biome.
|
|
18
|
+
*/
|
|
19
|
+
export function subjectServingBiome(subjects, biomeId, kind, id, enums) {
|
|
20
|
+
const owned = subjects.filter((subject) => isOwnedByBiome(subject, biomeId, enums));
|
|
21
|
+
const own = owned.find((subject) => subject.kind === kind && subject.id === id);
|
|
22
|
+
if (own !== undefined || kind !== enums.RuntimeImageSubjectKind.Service) {return own;}
|
|
23
|
+
return owned.find((subject) => (subject.members ?? []).some((member) => member.service === id));
|
|
24
|
+
}
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import { assertRosteredChartSetLock } from './edition-chart-set.mjs';
|
|
37
37
|
import { EditionLockFile } from './edition-constants.mjs';
|
|
38
38
|
import { editionsRoot } from './edition-workspace.mjs';
|
|
39
|
+
import { subjectServingBiome } from './image-lock-service-rows.mjs';
|
|
39
40
|
import { adoptCatalogueKernel } from './kernel-package.mjs';
|
|
40
41
|
import { compareStrings, imageLockWriteSchemaVersion, serializeJson, validateImmutableImageLock } from './lib.mjs';
|
|
41
42
|
import { pinnedSource, snapshotPinSource } from './pin-source.mjs';
|
|
@@ -142,7 +143,6 @@ export function projectVendorImages(catalogue, lock, enums) {
|
|
|
142
143
|
);
|
|
143
144
|
if (owners.length > 0) {subjects.push({ ...subject, owners });}
|
|
144
145
|
}
|
|
145
|
-
const have = new Set(subjects.filter((s) => s.owners.some((o) => o.kind === enums.RuntimeImageOwnerKind.Biome)).flatMap((s) => s.owners.map((o) => `${o.biomeId}\0${s.kind}\0${s.id}`)));
|
|
146
146
|
for (const biome of lock.biomes.filter((b) => b.source === undefined && b.target !== 'web')) {
|
|
147
147
|
const shared = new Set(Object.keys(biome.workerImages ?? {}));
|
|
148
148
|
const wanted = [
|
|
@@ -150,7 +150,7 @@ export function projectVendorImages(catalogue, lock, enums) {
|
|
|
150
150
|
...(biome.runtimeComponents ?? []).map((id) => [enums.RuntimeImageSubjectKind.RuntimeComponent, id]),
|
|
151
151
|
];
|
|
152
152
|
for (const [kind, id] of wanted) {
|
|
153
|
-
if (
|
|
153
|
+
if (subjectServingBiome(subjects, biome.id, kind, id, enums) === undefined) {
|
|
154
154
|
throw new CatalogueCeilingError(`the catalogue carries no image row for ${kind}:${id} of selected biome "${biome.id}"`);
|
|
155
155
|
}
|
|
156
156
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/xema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/xema-dev/xema-cli.git",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@xemahq/distribution-source-hash": "^0.2.2",
|
|
55
55
|
"@xemahq/dsl": "^0.24.0",
|
|
56
56
|
"@xemahq/identity-client": "^0.16.0",
|
|
57
|
-
"@xemahq/contracts": "^0.
|
|
57
|
+
"@xemahq/contracts": "^0.102.0",
|
|
58
58
|
"@xemahq/kernel-state-runtime": "^0.8.0",
|
|
59
59
|
"@xemahq/license-verifier": "^0.2.0",
|
|
60
60
|
"@xemahq/service-registry-nest": "^0.12.2",
|
|
@@ -92,6 +92,6 @@
|
|
|
92
92
|
"typecheck": "tsc --noEmit"
|
|
93
93
|
},
|
|
94
94
|
"xemaRelease": {
|
|
95
|
-
"sourceDigest": "sha256:
|
|
95
|
+
"sourceDigest": "sha256:97a574d113d6c30640832ec00008c3788c449ec45456db7b5d117c98460340cc"
|
|
96
96
|
}
|
|
97
97
|
}
|