@xemahq/xema 0.53.0 → 0.54.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/README.md +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/auth.d.ts +9 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +66 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/edition.d.ts.map +1 -1
- package/dist/commands/edition.js +1 -0
- package/dist/commands/edition.js.map +1 -1
- package/dist/edition/verify-image-evidence.bundle.mjs +916 -860
- package/dist/edition/verify-image-evidence.bundle.provenance.json +495 -489
- package/dist/runtime/edition/verb-map.d.ts +2 -1
- package/dist/runtime/edition/verb-map.d.ts.map +1 -1
- package/dist/runtime/edition/verb-map.js +2 -0
- package/dist/runtime/edition/verb-map.js.map +1 -1
- package/edition/README.md +54 -2
- package/edition/adapter-bundled-versions.mjs +2 -1
- package/edition/authorization-base.mjs +9 -8
- package/edition/biome-content.mjs +23 -29
- package/edition/candidate-edition.mjs +692 -0
- package/edition/checkout-indexed-source-repositories.mjs +6 -8
- package/edition/collected-refusals.mjs +59 -0
- package/edition/contract-authority.mjs +122 -0
- package/edition/cosign-certificate-constraints.mjs +18 -8
- package/edition/customer-edition-verbs.mjs +30 -8
- package/edition/develop-chart-set.mjs +7 -6
- package/edition/develop-edition-invariants.mjs +2 -1
- package/edition/develop-edition-resolve.mjs +109 -31
- package/edition/develop-edition.mjs +49 -8
- package/edition/develop-engine-image.mjs +95 -0
- package/edition/develop-image-probe.mjs +2 -1
- package/edition/develop-resolve-report.mjs +159 -0
- package/edition/develop-snapshot-inputs.mjs +4 -3
- package/edition/develop-verify-image-record.mjs +23 -4
- package/edition/edition-artifact.mjs +17 -7
- package/edition/edition-protocol.mjs +5 -2
- package/edition/images-from-record.mjs +362 -0
- package/edition/lib.mjs +1 -19
- package/edition/locked-bundle-signer.mjs +15 -3
- package/edition/operation-grant-admission.mjs +51 -9
- package/edition/resolve-distribution.mjs +95 -82
- package/edition/resolve-images.mjs +12 -5
- package/edition/shallow-checkout.mjs +18 -0
- package/edition/workspace-sections.mjs +23 -3
- package/package.json +7 -3
|
@@ -23,7 +23,8 @@ export declare enum EditionVerb {
|
|
|
23
23
|
Arming = "arming",
|
|
24
24
|
Pin = "pin",
|
|
25
25
|
Unpin = "unpin",
|
|
26
|
-
Ceiling = "ceiling"
|
|
26
|
+
Ceiling = "ceiling",
|
|
27
|
+
ContractAuthority = "contract-authority"
|
|
27
28
|
}
|
|
28
29
|
export declare enum EditionChartSetOperation {
|
|
29
30
|
Resolve = "resolve",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verb-map.d.ts","sourceRoot":"","sources":["../../../src/runtime/edition/verb-map.ts"],"names":[],"mappings":"AAKA,oBAAY,WAAW;IACrB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,cAAc,oBAAoB;IAClC,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,aAAa,mBAAmB;IAChC,GAAG,QAAQ;IACX,eAAe,qBAAqB;IACpC,eAAe,qBAAqB;IACpC,kBAAkB,yBAAyB;IAC3C,cAAc,oBAAoB;IAClC,QAAQ,aAAa;IACrB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,aAAa,mBAAmB;IAChC,QAAQ,cAAc;IACtB,cAAc,oBAAoB;IAClC,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,OAAO,YAAY;
|
|
1
|
+
{"version":3,"file":"verb-map.d.ts","sourceRoot":"","sources":["../../../src/runtime/edition/verb-map.ts"],"names":[],"mappings":"AAKA,oBAAY,WAAW;IACrB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,cAAc,oBAAoB;IAClC,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,aAAa,mBAAmB;IAChC,GAAG,QAAQ;IACX,eAAe,qBAAqB;IACpC,eAAe,qBAAqB;IACpC,kBAAkB,yBAAyB;IAC3C,cAAc,oBAAoB;IAClC,QAAQ,aAAa;IACrB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,aAAa,mBAAmB;IAChC,QAAQ,cAAc;IACtB,cAAc,oBAAoB;IAClC,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,iBAAiB,uBAAuB;CACzC;AAGD,oBAAY,wBAAwB;IAClC,OAAO,YAAY;IACnB,YAAY,kBAAkB;CAC/B;AAGD,oBAAY,mBAAmB;IAC7B,aAAa,mBAAmB;IAChC,uBAAuB,+BAA+B;IACtD,SAAS,cAAc;IACvB,WAAW,iBAAiB;IAC5B,cAAc,oBAAoB;IAClC,WAAW,iBAAiB;IAC5B,GAAG,QAAQ;CACZ;AAGD,oBAAY,wBAAwB;IAClC,QAAQ,aAAa;IACrB,YAAY,iBAAiB;IAC7B,WAAW,gBAAgB;IAC3B,SAAS,cAAc;CACxB;AAGD,oBAAY,gBAAgB;IAC1B,KAAK,UAAU;IACf,eAAe,qBAAqB;IACpC,kBAAkB,yBAAyB;CAC5C;AAGD,oBAAY,oBAAoB;IAC9B,OAAO,YAAY;IACnB,MAAM,WAAW;CAClB;AAGD,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,MAAM,CAAC,CAE1F,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CACvC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,KAAK,GAAG,WAAW,CAAC,cAAc,GAAG,WAAW,CAAC,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAwBnI,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAGtF,CAAC;AAEF,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,MAAM,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAK/F,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAUxH,CAAC;AAGF,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAE9C,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAI1E,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAEhC,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IAExC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAiDD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,CAoBtG"}
|
|
@@ -29,6 +29,7 @@ var EditionVerb;
|
|
|
29
29
|
EditionVerb["Pin"] = "pin";
|
|
30
30
|
EditionVerb["Unpin"] = "unpin";
|
|
31
31
|
EditionVerb["Ceiling"] = "ceiling";
|
|
32
|
+
EditionVerb["ContractAuthority"] = "contract-authority";
|
|
32
33
|
})(EditionVerb || (exports.EditionVerb = EditionVerb = {}));
|
|
33
34
|
var EditionChartSetOperation;
|
|
34
35
|
(function (EditionChartSetOperation) {
|
|
@@ -88,6 +89,7 @@ exports.EDITION_VERB_ENTRY = {
|
|
|
88
89
|
[EditionVerb.Pin]: 'edition-pin.mjs',
|
|
89
90
|
[EditionVerb.Unpin]: 'edition-unpin.mjs',
|
|
90
91
|
[EditionVerb.Ceiling]: 'edition-ceiling.mjs',
|
|
92
|
+
[EditionVerb.ContractAuthority]: 'contract-authority.mjs',
|
|
91
93
|
};
|
|
92
94
|
exports.EDITION_CHART_SET_ENTRY = {
|
|
93
95
|
[EditionChartSetOperation.Resolve]: 'resolve-chart-set.mjs',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verb-map.js","sourceRoot":"","sources":["../../../src/runtime/edition/verb-map.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"verb-map.js","sourceRoot":"","sources":["../../../src/runtime/edition/verb-map.ts"],"names":[],"mappings":"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"}
|
package/edition/README.md
CHANGED
|
@@ -38,6 +38,7 @@ Each takes the roots below plus its own arguments (`--check`, an edition id, ...
|
|
|
38
38
|
| `release-edition.mjs` (`xema edition release`) | per verb: `freeze-sources` data; `target` none; `check-existing` data, cache; `resolve` data, editions, sources, cache |
|
|
39
39
|
| `release-edition-artifact.mjs` (`xema edition artifact`) | data, editions, kernel |
|
|
40
40
|
| `trust-policy-arming-verb.mjs` (`xema edition arming`) | data, kernel |
|
|
41
|
+
| `contract-authority.mjs` (`xema edition contract-authority`) | none (the `@xemahq/contracts` this CLI ships) |
|
|
41
42
|
| `build-biome-index.mjs`, `build-platform-service-index.mjs`, `build-runtime-image-source-index.mjs` | data, sources, kernel |
|
|
42
43
|
| `checkout-indexed-source-repositories.mjs` | data, sources |
|
|
43
44
|
| `why.mjs` | editions, kernel |
|
|
@@ -89,6 +90,7 @@ xema edition chart-set <resolve|source-commit> ...
|
|
|
89
90
|
xema edition arming --channel <release|develop> --data-root <dir> --kernel <dir>
|
|
90
91
|
xema edition verify-evidence <id> --descriptor <abs path> [--json]
|
|
91
92
|
xema edition evidence <assemble-input|check-committed|plan-refresh|statement|assemble-set|oci> ...
|
|
93
|
+
xema edition contract-authority > contract-authority.json # the full kernel contract authority of the @xemahq/contracts this CLI ships, canonical JSON: the --contract-authority <file> of a publisher's public-input run, no root flags (see Third-party sources)
|
|
92
94
|
xema edition evidence assemble-third-party-input --bundle <oci repository>@sha256:<hex> --contract-authority <file> --image <image repository>@sha256:<hex> --subject-id <component image name> --provenance <absolute exported SLSA v1 predicate> --registry-credentials <file> --output <path> [--ttl-seconds <n>] # a third-party publisher's producer input, no root flags (see Third-party sources)
|
|
93
95
|
```
|
|
94
96
|
|
|
@@ -117,14 +119,44 @@ The develop graph is the data root's first-party repositories, declared in `edit
|
|
|
117
119
|
|
|
118
120
|
```json
|
|
119
121
|
"firstPartySources": {
|
|
120
|
-
"repos/xema-base": { "sourceId": "xema-base", "repositoryUrl": "https://git.example.com/acme/xema-base.git" }
|
|
122
|
+
"repos/xema-base": { "sourceId": "xema-base", "repositoryUrl": "https://git.example.com/acme/xema-base.git", "imageOrigin": "workspace" },
|
|
123
|
+
"submodules/xema-host-web": { "sourceId": "xema-host-web", "repositoryUrl": "https://git.example.com/acme/xema-host-web.git", "imageOrigin": "satellite" }
|
|
121
124
|
}
|
|
122
125
|
```
|
|
123
126
|
|
|
124
127
|
- Each key is a repository handle (`repos/<x>` or `submodules/<x>`); `sourceId` is its kebab-case source id; `repositoryUrl` is canonical HTTPS under `sourceRepositoryUrlPrefix`. Both are unique. The retired string form (`"repos/x": "x"`) is refused with `RetiredFirstPartySourceShapeError`.
|
|
128
|
+
- `imageOrigin` says where the source's images come from on the everyday lane: `workspace` (built by the job in the aggregator workspace) or `satellite` (a producer outside it, such as `submodules/xema-host-web`, that publishes its own signed develop digest). The parse accepts a source without it and fills in no default; `--images-from` refuses such a source (see below).
|
|
125
129
|
- `xema edition develop freeze-graph` pins every declared repository at the `develop` head of its declared URL; overrides may name any of them. The snapshot's `repositoryPins` (`develop resolve`, `checkout-indexed-source-repositories.mjs --snapshot-pins`) are exactly these repositories. The runtime image source index's `repositoryPins` are release pins and are not read on develop.
|
|
126
130
|
- A first-party repository is in the develop graph before any release pins it. The converse is checked offline: every `repositoryPins` entry must be declared first-party at the same `repositoryUrl`.
|
|
127
131
|
|
|
132
|
+
## Develop images from a build record
|
|
133
|
+
|
|
134
|
+
`xema edition develop resolve <id> ... --images-from <file>` takes every first-party image of the edition from the everyday job's build record instead of the registry probe: no probe, no rehash, and no digest read from the registry. The record (`images-from-record.mjs`, schema version 1, strict: unknown keys refused, each list sorted by `subject`, a subject in at most one entry):
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"schemaVersion": 1,
|
|
139
|
+
"images": [
|
|
140
|
+
{
|
|
141
|
+
"subject": "service:biome-host-api",
|
|
142
|
+
"repository": "registry.example.com/acme/dev/biome-host-api",
|
|
143
|
+
"contentHash": "<64 hex: the image-input hash, the tag>",
|
|
144
|
+
"digest": "sha256:<64 hex: the manifest or index digest>",
|
|
145
|
+
"platforms": [{ "os": "linux", "architecture": "amd64" }],
|
|
146
|
+
"sourceSha": "<40 hex>"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"satellites": [ { "subject": "host:xema-host-web", "...": "the same six fields" } ]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- `subject` is `<kind>:<id>`, the key of the subject in `images.lock.json`. `repository` is the subject's develop repository. `platforms` must include every platform the edition requires. `sourceSha` must be the commit the snapshot pins for the subject's repository.
|
|
154
|
+
- `images` are the images the job built or reused by content-hash tag. `satellites` are digests of first-party sources the job does not build (for example `submodules/xema-host-web`): each is admitted only when the producer's own develop `.github/workflows/ci.yaml` build record, cosign-verified as `select-records` verifies it (the data root's `record-build.yaml` at `refs/heads/develop`, called by the producer, issuer `https://token.actions.githubusercontent.com`), is at `sourceSha` and lists the exact `repository`, `digest` and `contentHash`. The producer is the subject repository's declared `firstPartySources` URL, never a record field. The records live under `--registry`'s `build-records/<repo>`.
|
|
155
|
+
- Coverage is exact: a subject missing from the record, an entry that is not a first-party subject of the edition, or any contradicted field refuses the resolve, all named at once, with no probe fallback. `contentHash` and `sourceSha` are written to the lock as given; the lock's `imageRef` and `imageDigest` are the record's `repository` and `digest`. A third-party subject is not recorded and keeps its pinned seal.
|
|
156
|
+
- Which list an entry sits in is not the record's choice. Each entry must be in the list its source's declared `imageOrigin` names: `workspace` sources in `images`, `satellite` sources in `satellites`. An entry in the other list (for example a satellite listed under `images`, which would skip the cosign verify), or an entry whose source declares no `imageOrigin`, refuses the resolve, with every problem named at once.
|
|
157
|
+
- The develop target tag takes the record's digest (sha256 of its canonical JSON, entries by subject and platforms sorted) as one more input, `imageBuildRecord`, so the same pins with another satellite digest are another artifact. `develop target --images-from <file>` prints the same target the resolve does.
|
|
158
|
+
- Without `--images-from` the resolve probes the registry and seals from it as before, and the tag inputs are unchanged. A customer resolve or target refuses the flag.
|
|
159
|
+
|
|
128
160
|
## Develop plane invariants
|
|
129
161
|
|
|
130
162
|
`xema edition develop resolve` asserts the capability-domain reservation table and biome confinement on the candidate it resolves, against the develop graph it froze, before any later phase. On develop they are asserted only there; `xema edition check` asserts them over the committed locks.
|
|
@@ -147,7 +179,7 @@ The edition library builds, validates and verifies evidence statements; it never
|
|
|
147
179
|
|
|
148
180
|
## Kernel protocol and pins
|
|
149
181
|
|
|
150
|
-
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 v28, v30, v31, v32, v33, v34, v35, v36, v37, v38 and
|
|
182
|
+
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 v28, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39 and v40 (no published kernel declares v29; a CLI lists a protocol only while every kernel published under it exports what the CLI imports; v27 and older kernels lack `serviceImageSubjects`, so a data root whose pinned kernel speaks v27 or older stays on an earlier CLI), pinned to its digest and vendored, 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.
|
|
151
183
|
|
|
152
184
|
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`.
|
|
153
185
|
|
|
@@ -162,6 +194,7 @@ A develop edition does not take the kernel's develop head blindly: `xema edition
|
|
|
162
194
|
|
|
163
195
|
- **Zero-config.** A data root with no `third-party-source-pins.json`, an empty one or an unparsable one has NO third-party source: every `kind: oci` declared source and every third-party image subject is refused, naming the loader's reason. The pin file is the explicit grant; a trust-policy row alone grants nothing. When the file exists, its sha256 is part of the evidence trust pin, so it moves only together with `xema edition repin-evidence-trust`.
|
|
164
196
|
- **Publisher input.** The publisher's own GitHub-hosted workflow, on `refs/heads/main`, assembles the producer input of each image with `xema edition evidence assemble-third-party-input` (usage above), one run per image. It runs on public inputs only: this CLI and the `@xemahq/contracts` it ships (both from npm), the publisher's checkout at `GITHUB_WORKSPACE` (holding `GITHUB_SHA`), its own registry credential declaration (`--registry-credentials`, the `image-registry-credentials.json` format, naming environment variables, never a secret) and the `GITHUB_*` context. It takes no root flag and reads no data root. `--contract-authority` is the kernel contract authority object the vendor's evidence trust pin names; it must be the kernel this CLI ships, so the publisher installs the matching CLI version. The subject is the bundle's (`--bundle`, read by digest) `oci-image` service or worker component named `--subject-id`; `path` is the directory of the one `xema-biome.json` at `GITHUB_SHA` whose hash is the bundle's; `sourceTreeHash` is hashed over the checkout with no cross-repo inputs (publisher-attested); the image is read by digest (`--image`) and must carry its cosign SLSA v1 and SBOM attestations; the builder digests come from the exported predicate (`--provenance`, VCS revision `GITHUB_SHA`). The lifetime is `--ttl-seconds` or the first-party default (72h); the trust policy's `maxProducerTtlSeconds` ceiling is enforced by the vendor's third-party pin writer (`index runtime-image-source --trusted-write --third-party`) and by `verify-evidence`, and the signer rows and image ownership are checked by the pin writer. It refuses unless `RUNNER_ENVIRONMENT` is `github-hosted` and `GITHUB_REF` is `refs/heads/main`. The output is the exact input `xema edition evidence statement producer` accepts.
|
|
197
|
+
- **Publisher contract authority.** The `--contract-authority <file>` comes from `xema edition contract-authority`, also on public inputs only: it prints the full `KernelContractAuthority` of the `@xemahq/contracts` this CLI ships, read from that package's own export `@xemahq/contracts/edition-protocol/contract-authority.json` (the kernel's release derives it at publish time; `sourceCommit` is the commit as the kernel release states it, carried, not proven, while the digest and `sourcePaths` are proven against the package). It is parsed with `KernelContractAuthoritySchema`, refused unless its `contentDigest` is the bundled edition protocol digest and the bundled kernel is that authority, and printed as canonical JSON. A kernel without the file (a dev build, or a release older than the file) is refused by name; there is no fallback.
|
|
165
198
|
- **Publisher evidence (public-input mode).** The rest of the publisher's run uses the same verbs as first party with `--contract-authority <file>` in place of `--data-root`/`--kernel`: `xema edition evidence statement producer stage` (no OIDC), a keyless `cosign attest-blob --new-bundle-format` of each staged statement in an `id-token: write` job, `statement producer accept --cosign <abs path>` (no OIDC), then `oci attach-plan`, `oras attach` and `oci validate`. Passing both modes, or neither, is refused by name. The authority and schemas come from the file and the `@xemahq/contracts` this CLI bundles, through the one resolution `assemble-third-party-input` uses. Accept verifies every bundle's signature but holds cosign to no version: the vendor's admission re-verifies with its pinned cosign. The publisher installs the xema CLI whose bundled `@xemahq/contracts` matches the authority; an authority whose contracts digest is not the bundled one is refused, naming both digests.
|
|
166
199
|
- **Seal.** A third-party image subject is sealed BY DIGEST from its pin: it keeps the publisher's `imageRef`, its platforms are read at `<imageRef>@<manifestDigest>`, and its `contentHash` (the publisher's `sourceTreeHash`) is never used as a tag, a develop coordinate, a cache key or a build-ledger key. It is not a develop-coverage subject and is excluded from the first-party fleet-coordinate verdict. Its producer evidence in the edition's evidence set is the committed evidence the pin records, checked byte for byte against the pin's digests.
|
|
167
200
|
- **Revocation.** A sealed lock keeps its seal-time verdict; there is no expiry machinery. To revoke a source: remove its pin and its trust-policy rows, regenerate the runtime image source index, run `xema edition repin-evidence-trust`, and reseal every edition that includes the biome. An edition already delivered is not recalled.
|
|
@@ -215,6 +248,25 @@ A customer verb takes no `--kernel` (it is refused) and needs no kernel checkout
|
|
|
215
248
|
|
|
216
249
|
The adapter host refuses at mount an adapter whose packed `package.json` `xemaBundled` entry for `@xemahq/contracts` or `@xemahq/biome-sdk` is missing or not caret-compatible with the host's own resolved copy (same major; same minor too while the major is 0; an unparsable version is incompatible). The edition build refuses the same first, in `adapter-bundled-versions.mjs`: every lock biome host module of the `xema-adapter-host` ABI must carry an npm bundle source, whose published manifest is read from `https://registry.npmjs.org/<name>/<version>` without a credential. The host's versions are the `hostPackageVersions` of the `biome-adapter-host` row of the biome index (read from the host source's `pnpm-lock.yaml` when the index is built; the distribution lock never carries it) and, for a customer, of the same row in the catalogue. Resolve (vendor, develop, customer) and seal (vendor and `--definition`) run the check and report all refusals together, each with one of `adapter-bundle-version-mismatch`, `adapter-host-unpinned` (no host row or no `hostPackageVersions`), `adapter-not-published` (the registry answers 404) or `unsupported-bundle-source` (not npm).
|
|
217
250
|
|
|
251
|
+
## Candidate editions (a boot test, never a deploy)
|
|
252
|
+
|
|
253
|
+
`@xemahq/xema/candidate-edition` re-seals a pinned develop edition with ONE repository's candidate commit, so that repository's CI can boot the composed member set through the production path against locks that match the candidate. Two calls:
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
import { fetchPinnedEditionCheckouts, resealCandidateEdition } from '@xemahq/xema/candidate-edition';
|
|
257
|
+
const candidate = { repo: 'repos/xema-base', checkoutDir: '/abs/xema-base' };
|
|
258
|
+
const checkouts = await fetchPinnedEditionCheckouts({ tripleDir, cacheDir, dataRootDir, candidate, env });
|
|
259
|
+
await resealCandidateEdition({ tripleDir, checkouts, candidate, outDir, deployment: { id, runtimeNamespace } });
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
- `tripleDir` is a pulled develop edition artifact (`xema-edition.json` plus its locks); its `provenance.pins` are the pins. A customer or release edition is refused.
|
|
263
|
+
- `fetchPinnedEditionCheckouts` is the ONLY network step. A cached checkout is built in a staging directory and renamed into place only once it is complete (the kernel once its build succeeded), so a failed run never leaves a partial checkout to be reused. Local git commands run with PATH and HOME only. It clones every checkout the develop resolve reads at its pin (the kernel, built as `develop-edition.yaml` builds it, and every develop-graph repository but the candidate, with the extra commits the resolve reads) into `cacheDir/checkouts/<pin key>/<commit>`, and every declared source into the external-source cache. The data root is cloned locally from `dataRootDir`, the caller's checkout of it at its pin, because the data root declares every other repository and the credential that reads them. Credentials are read only from the `env` the caller passes. A warm cache runs no network command and no build. Every cached checkout must be at its pin and clean.
|
|
264
|
+
- The calls configure the process-global edition workspace while they run: run one at a time in a process.
|
|
265
|
+
- `resealCandidateEdition` runs OFFLINE. The candidate checkout must be clean (tracked files at HEAD), and the candidate commit replaces its pin. It reruns the develop resolve's distribution steps (snapshot inputs, resolve, bundle signers, plane invariants, operation admission) and `composeAuthorizationBase` (`XEMA_FGA_CLI`). It seals the distribution lock with the kernel's `sealDistributionLock` and carries `images.lock.json` byte for byte. It does not run the steps that read a registry: the images resolve and seal, the adapter-bundle check and the chart set.
|
|
266
|
+
- The output directory holds `distribution.lock.json`, `images.lock.json`, `authorization.lock.json`, `resolved-deployment.json` and `candidate-content.json`. The resolved deployment is the kernel's `resolveUnsplitDeployment` over exactly those lock bytes. It names the registry `candidate.invalid` and the version `0.0.0-candidate`.
|
|
267
|
+
- **Unsigned and not deployable.** The output is a plain directory, never an edition. It has no `xema-edition.json`, is never pushed as an OCI artifact and is never signed, and admission needs the cosign-signed edition artifact. Its resolved deployment is the UNSPLIT variant, which `verifyResolvedDeployment` refuses (`unsplit-not-accepted`) unless the caller opts in with `{ accept: 'unsplit' }`.
|
|
268
|
+
- **The candidate content record.** A biome that ships images from its own repository has its content read where its images were built. The carried images were built at the pinned commit, so `candidate-content.json` records `{ <repo>: <candidate commit> }`, bound to the distribution lock bytes by `distributionLockSha256`, to the edition by `distributionId`, and to the candidate: it holds exactly one entry, the candidate repository at its checkout's HEAD, and any other record is refused. The seal and `verifyCandidateContentHashes` pass the record to biome-content.mjs as `contentCommits`. A record that names a commit whose content is not the lock's is refused. A triple without a record is verified exactly as any lock is. The record is a file beside the locks, because the kernel's lock schema is strict and has no field for it.
|
|
269
|
+
|
|
218
270
|
## Tests
|
|
219
271
|
|
|
220
272
|
```bash
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// resolved copy. The mount check stays the last line; this is the first.
|
|
8
8
|
|
|
9
9
|
import { ADAPTER_HOST_BIOME_ID, BUNDLED_PACKAGES, isCaretCompatible } from './adapter-host-versions.mjs';
|
|
10
|
+
import { RefusalError } from './collected-refusals.mjs';
|
|
10
11
|
import { loadKernelBiomeContracts } from './lib.mjs';
|
|
11
12
|
import { compareStrings } from './string-order.mjs';
|
|
12
13
|
|
|
@@ -17,7 +18,7 @@ export const AdapterBundleVersionErrorCode = Object.freeze({
|
|
|
17
18
|
UnsupportedSource: 'unsupported-bundle-source',
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
export class AdapterBundleVersionError extends
|
|
21
|
+
export class AdapterBundleVersionError extends RefusalError {
|
|
21
22
|
constructor({ code, biomeId, packageName, bundled, host }) {
|
|
22
23
|
super(
|
|
23
24
|
`${code}: biome "${biomeId}" package "${packageName}" bundled ${JSON.stringify(bundled)} ` +
|
|
@@ -32,6 +32,7 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync
|
|
|
32
32
|
import { tmpdir } from 'node:os';
|
|
33
33
|
import { dirname, join } from 'node:path';
|
|
34
34
|
|
|
35
|
+
import { RefusalError } from './collected-refusals.mjs';
|
|
35
36
|
import { assertKernelEditionProtocol } from './edition-protocol.mjs';
|
|
36
37
|
|
|
37
38
|
/** Where a biome keeps its module, relative to its manifest directory (plan §2.1). */
|
|
@@ -68,11 +69,11 @@ export function readBiomeAuthorizationModuleAt(manifestDirectory, readText, rel)
|
|
|
68
69
|
try {
|
|
69
70
|
envelope = JSON.parse(envelopeText);
|
|
70
71
|
} catch (err) {
|
|
71
|
-
throw new
|
|
72
|
+
throw new RefusalError(`${rel}: ${base}/${AUTHORIZATION_ENVELOPE_FILENAME} is not JSON: ${err.message}`);
|
|
72
73
|
}
|
|
73
74
|
const files = Array.isArray(envelope?.files) ? envelope.files : null;
|
|
74
75
|
if (!files || files.length === 0 || typeof envelope.tests !== 'string') {
|
|
75
|
-
throw new
|
|
76
|
+
throw new RefusalError(
|
|
76
77
|
`${rel}: ${base}/${AUTHORIZATION_ENVELOPE_FILENAME} must name its module files ("files") ` +
|
|
77
78
|
'and its REQUIRED OpenFGA test file ("tests").',
|
|
78
79
|
);
|
|
@@ -80,7 +81,7 @@ export function readBiomeAuthorizationModuleAt(manifestDirectory, readText, rel)
|
|
|
80
81
|
const read = (name) => {
|
|
81
82
|
const contents = readText(`${base}/${name}`);
|
|
82
83
|
if (contents === null) {
|
|
83
|
-
throw new
|
|
84
|
+
throw new RefusalError(`${rel}: the authorization envelope names ${base}/${name}, which does not exist at the pinned commit.`);
|
|
84
85
|
}
|
|
85
86
|
return { name, contents };
|
|
86
87
|
};
|
|
@@ -110,10 +111,10 @@ export function editionAuthorizationModuleInputs(lockBiomes, indexById, kernel)
|
|
|
110
111
|
const inputs = [];
|
|
111
112
|
for (const { id, version } of lockBiomes) {
|
|
112
113
|
const entry = indexById.get(id);
|
|
113
|
-
if (!entry) {throw new
|
|
114
|
+
if (!entry) {throw new RefusalError(`edition biome "${id}" is missing from the biome index`);}
|
|
114
115
|
if (!entry.authorizationModule) {continue;}
|
|
115
116
|
if (kernel === null) {
|
|
116
|
-
throw new
|
|
117
|
+
throw new RefusalError(
|
|
117
118
|
`edition biome "${id}" ships an authorization module, but the pinned kernel ships no composer to stamp or compose it.`,
|
|
118
119
|
);
|
|
119
120
|
}
|
|
@@ -200,7 +201,7 @@ export function composeEditionAuthorizationBase({ distributionId, inputs, kernel
|
|
|
200
201
|
});
|
|
201
202
|
} catch (err) {
|
|
202
203
|
if (Array.isArray(err?.violations)) {
|
|
203
|
-
throw new
|
|
204
|
+
throw new RefusalError(`${distributionId}: the authorization base was REFUSED by the kernel composer.\n${err.message}`);
|
|
204
205
|
}
|
|
205
206
|
throw err;
|
|
206
207
|
}
|
|
@@ -260,13 +261,13 @@ export function fgaComposedModelTestRunner(bin) {
|
|
|
260
261
|
writeFileSync(join(root, f.name), f.contents);
|
|
261
262
|
}
|
|
262
263
|
if (composed.testFiles.length === 0) {
|
|
263
|
-
throw new
|
|
264
|
+
throw new RefusalError('the composed base carries no test file — every module ships one, the platform modules included.');
|
|
264
265
|
}
|
|
265
266
|
for (const t of composed.testFiles) {
|
|
266
267
|
try {
|
|
267
268
|
execFileSync(bin, ['model', 'test', '--tests', t.name], { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
268
269
|
} catch (err) {
|
|
269
|
-
throw new
|
|
270
|
+
throw new RefusalError(
|
|
270
271
|
`${t.owner}: ${t.name} FAILED against the composed edition base:\n` +
|
|
271
272
|
`${String(err.stdout ?? '').trim()}\n${String(err.stderr ?? '').trim()}`,
|
|
272
273
|
);
|
|
@@ -22,15 +22,7 @@ import { relative, sep } from 'node:path';
|
|
|
22
22
|
import { assertCustomerLockWithinCatalogueCeiling } from './catalogue.mjs';
|
|
23
23
|
import { readGitJsonAtCommit } from './lib.mjs';
|
|
24
24
|
import { assertLockBundleSigners } from './locked-bundle-signer.mjs';
|
|
25
|
-
import {
|
|
26
|
-
assertInstalledOperationCeilingAdmitted,
|
|
27
|
-
assertOperationGrantsAdmitted,
|
|
28
|
-
assertExactAudiencesAdmitted,
|
|
29
|
-
assertOrganizationSweepsAdmitted,
|
|
30
|
-
assertEventSubscriptionsAdmitted,
|
|
31
|
-
assertOrgContextRelaysAdmitted,
|
|
32
|
-
assertStoreWorkloadCeilingAdmitted,
|
|
33
|
-
} from './operation-grant-admission.mjs';
|
|
25
|
+
import { admitDistributionLock } from './operation-grant-admission.mjs';
|
|
34
26
|
|
|
35
27
|
/** A biome whose recomputed content hash is not the lock's, or whose inputs cannot be recomputed. */
|
|
36
28
|
export class BiomeContentHashError extends Error {
|
|
@@ -45,9 +37,16 @@ export class BiomeContentHashError extends Error {
|
|
|
45
37
|
* bundle) is pinned where its images lock row is; a declared source at its
|
|
46
38
|
* locked commit; a content-only first-party biome at the vendored-source pin
|
|
47
39
|
* (`vendoredCommit(repo)`), the axis its manifest hash was read on.
|
|
40
|
+
*
|
|
41
|
+
* `contentCommits` (repo -> commit) is a CANDIDATE edition's recorded override
|
|
42
|
+
* (candidate-edition.mjs): every first-party biome of a named repo has its content
|
|
43
|
+
* at the recorded commit, not at its carried images' `sourceCommit`. Absent, the
|
|
44
|
+
* rule above is the whole rule. Nothing reads it but a caller that holds the record.
|
|
48
45
|
*/
|
|
49
|
-
function pinnedCommit({ biome, imageLock, ownerKinds, vendoredCommit }) {
|
|
46
|
+
function pinnedCommit({ biome, imageLock, ownerKinds, vendoredCommit, contentCommits }) {
|
|
50
47
|
if (biome.source !== undefined) {return biome.source.commit;}
|
|
48
|
+
const recorded = contentCommits?.get(biome.repo);
|
|
49
|
+
if (recorded !== undefined) {return recorded;}
|
|
51
50
|
// Only subjects from the biome's OWN repo pin its content commit; a runtime component it
|
|
52
51
|
// launches from another repo is owned (and digest-bound) but is not where the biome lives.
|
|
53
52
|
const owned = imageLock.subjects.filter(
|
|
@@ -125,11 +124,11 @@ async function readLockedManifest({ schemas, biome, commit, locate }) {
|
|
|
125
124
|
* A manifest that cannot be read at its pinned commit, or that is not the manifest
|
|
126
125
|
* the lock names (`sourceManifestHash`), is refused, naming the biome.
|
|
127
126
|
*/
|
|
128
|
-
export async function pinnedBiomeManifests({ schemas, lock, imageLock, locate, vendoredCommit }) {
|
|
127
|
+
export async function pinnedBiomeManifests({ schemas, lock, imageLock, locate, vendoredCommit, contentCommits }) {
|
|
129
128
|
const ownerKinds = schemas.RuntimeImageOwnerKind;
|
|
130
129
|
const manifests = [];
|
|
131
130
|
for (const biome of [...lock.biomes].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))) {
|
|
132
|
-
const sourceCommit = pinnedCommit({ biome, imageLock, ownerKinds, vendoredCommit });
|
|
131
|
+
const sourceCommit = pinnedCommit({ biome, imageLock, ownerKinds, vendoredCommit, contentCommits });
|
|
133
132
|
let manifest;
|
|
134
133
|
try {
|
|
135
134
|
({ manifest } = await readLockedManifest({ schemas, biome, commit: sourceCommit, locate }));
|
|
@@ -143,9 +142,9 @@ export async function pinnedBiomeManifests({ schemas, lock, imageLock, locate, v
|
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
/** The three facts of a biome recomputed from a checkout of its source at the pinned commit. */
|
|
146
|
-
async function sourceFacts({ schemas, biome, imageLock, locate, vendoredCommit }) {
|
|
145
|
+
async function sourceFacts({ schemas, biome, imageLock, locate, vendoredCommit, contentCommits }) {
|
|
147
146
|
const ownerKinds = schemas.RuntimeImageOwnerKind;
|
|
148
|
-
const commit = pinnedCommit({ biome, imageLock, ownerKinds, vendoredCommit });
|
|
147
|
+
const commit = pinnedCommit({ biome, imageLock, ownerKinds, vendoredCommit, contentCommits });
|
|
149
148
|
const { repoDirectory, repoRelativePath, sourceManifestHash } = await readLockedManifest({ schemas, biome, commit, locate });
|
|
150
149
|
return {
|
|
151
150
|
sourceManifestHash,
|
|
@@ -232,9 +231,10 @@ function assertLockNamesCatalogue({ schemas, lock, catalogue, catalogueDigest, s
|
|
|
232
231
|
* @param {object} [request.catalogue] customer mode: the digest-pinned catalogue vendor biomes are taken from
|
|
233
232
|
* @param {string} [request.catalogueDigest] customer mode: the digest of that catalogue; the lock must carry the same one
|
|
234
233
|
* @param {readonly string[]} [request.storePublisherAnchorKeys] customer mode: the definition's Store publisher selection (absent = none)
|
|
234
|
+
* @param {Map<string, string>} [request.contentCommits] a candidate edition's recorded override: repo -> the commit its first-party biomes' content is read at
|
|
235
235
|
* @returns {Promise<Map<string, string>>} biome id -> BiomeContentHash
|
|
236
236
|
*/
|
|
237
|
-
export async function computeBiomeContentHashes({ schemas, lock, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, sourceFactsById }) {
|
|
237
|
+
export async function computeBiomeContentHashes({ schemas, lock, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, sourceFactsById, contentCommits }) {
|
|
238
238
|
if (catalogue !== undefined) {assertLockNamesCatalogue({ schemas, lock, catalogue, catalogueDigest, storePublisherAnchorKeys });}
|
|
239
239
|
const hashes = new Map();
|
|
240
240
|
for (const biome of lock.biomes) {
|
|
@@ -242,7 +242,7 @@ export async function computeBiomeContentHashes({ schemas, lock, imageLock, loca
|
|
|
242
242
|
catalogue !== undefined && biome.source === undefined
|
|
243
243
|
? await catalogueFacts({ schemas, biome, imageLock, catalogue })
|
|
244
244
|
: sourceFactsById === undefined
|
|
245
|
-
? await sourceFacts({ schemas, biome, imageLock, locate, vendoredCommit })
|
|
245
|
+
? await sourceFacts({ schemas, biome, imageLock, locate, vendoredCommit, contentCommits })
|
|
246
246
|
: precomputedFacts(sourceFactsById, biome);
|
|
247
247
|
hashes.set(biome.id, await schemas.computeBiomeContentHash(facts));
|
|
248
248
|
}
|
|
@@ -257,10 +257,10 @@ export async function computeBiomeContentHashes({ schemas, lock, imageLock, loca
|
|
|
257
257
|
*
|
|
258
258
|
* @returns {Promise<Map<string, object>>} biome id -> the three source facts
|
|
259
259
|
*/
|
|
260
|
-
export async function readBiomeSourceFacts({ schemas, lock, imageLock, locate, vendoredCommit }) {
|
|
260
|
+
export async function readBiomeSourceFacts({ schemas, lock, imageLock, locate, vendoredCommit, contentCommits }) {
|
|
261
261
|
const facts = new Map();
|
|
262
262
|
for (const biome of lock.biomes) {
|
|
263
|
-
facts.set(biome.id, await sourceFacts({ schemas, biome, imageLock, locate, vendoredCommit }));
|
|
263
|
+
facts.set(biome.id, await sourceFacts({ schemas, biome, imageLock, locate, vendoredCommit, contentCommits }));
|
|
264
264
|
}
|
|
265
265
|
return facts;
|
|
266
266
|
}
|
|
@@ -291,16 +291,10 @@ export async function biomeSourceTreeIds({ schemas, lock, imageLock, locate, ven
|
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
/** Seal: the unsealed lock + the recomputed hashes -> the kernel's `sealDistributionLock`. */
|
|
294
|
-
export async function sealLock({ schemas, unsealed, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, sourceFactsById, bundleSigners }) {
|
|
294
|
+
export async function sealLock({ schemas, unsealed, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, sourceFactsById, bundleSigners, contentCommits }) {
|
|
295
295
|
assertLockBundleSigners({ lock: unsealed, selection: bundleSigners, schemas });
|
|
296
|
-
const hashes = await computeBiomeContentHashes({ schemas, lock: unsealed, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, sourceFactsById });
|
|
297
|
-
|
|
298
|
-
assertOrganizationSweepsAdmitted(schemas, unsealed);
|
|
299
|
-
assertExactAudiencesAdmitted(schemas, unsealed);
|
|
300
|
-
assertOrgContextRelaysAdmitted(schemas, unsealed);
|
|
301
|
-
assertEventSubscriptionsAdmitted(schemas, unsealed);
|
|
302
|
-
assertInstalledOperationCeilingAdmitted(schemas, unsealed);
|
|
303
|
-
assertStoreWorkloadCeilingAdmitted(schemas, unsealed);
|
|
296
|
+
const hashes = await computeBiomeContentHashes({ schemas, lock: unsealed, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, sourceFactsById, contentCommits });
|
|
297
|
+
admitDistributionLock(schemas, unsealed);
|
|
304
298
|
return schemas.sealDistributionLock(unsealed, hashes);
|
|
305
299
|
}
|
|
306
300
|
|
|
@@ -308,8 +302,8 @@ export async function sealLock({ schemas, unsealed, imageLock, locate, vendoredC
|
|
|
308
302
|
* Verify: recompute every biome's hash and REFUSE a mismatch, naming the biome.
|
|
309
303
|
* The lock's own field is never trusted; a missing or extra biome is a mismatch.
|
|
310
304
|
*/
|
|
311
|
-
export async function verifyBiomeContentHashes({ schemas, lock, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, bundleSigners }) {
|
|
312
|
-
const expected = await computeBiomeContentHashes({ schemas, lock, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys });
|
|
305
|
+
export async function verifyBiomeContentHashes({ schemas, lock, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, bundleSigners, contentCommits }) {
|
|
306
|
+
const expected = await computeBiomeContentHashes({ schemas, lock, imageLock, locate, vendoredCommit, catalogue, catalogueDigest, storePublisherAnchorKeys, contentCommits });
|
|
313
307
|
assertLockBundleSigners({ lock, selection: bundleSigners, schemas });
|
|
314
308
|
const mismatched = lock.biomes
|
|
315
309
|
.filter((biome) => biome.biomeContentHash !== expected.get(biome.id))
|