@xemahq/xema 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/edition.d.ts.map +1 -1
- package/dist/commands/edition.js +8 -7
- package/dist/commands/edition.js.map +1 -1
- package/dist/dev/env-defaults.d.ts.map +1 -1
- package/dist/dev/env-defaults.js +0 -1
- package/dist/dev/env-defaults.js.map +1 -1
- package/dist/edition/verify-image-evidence.bundle.mjs +231 -50
- package/dist/edition/verify-image-evidence.bundle.provenance.json +55 -43
- 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/dist/runtime/runner/chart-set-lock.d.ts +4 -1
- package/dist/runtime/runner/chart-set-lock.d.ts.map +1 -1
- package/dist/runtime/runner/chart-set-lock.js +39 -4
- package/dist/runtime/runner/chart-set-lock.js.map +1 -1
- package/edition/README.md +76 -41
- package/edition/build-biome-index.mjs +1 -1
- package/edition/build-platform-service-index.mjs +1 -1
- package/edition/build-runtime-image-source-index.mjs +64 -20
- package/edition/catalogue-fetch.mjs +36 -9
- package/edition/catalogue-pin.mjs +71 -0
- package/edition/catalogue.mjs +11 -0
- package/edition/chart-set-source-commit.mjs +17 -7
- package/edition/checkout-indexed-source-repositories.mjs +17 -17
- package/edition/customer-flags.mjs +0 -1
- package/edition/develop-customer-edition.mjs +23 -5
- package/edition/develop-edition.mjs +147 -48
- package/edition/develop-freeze.mjs +69 -25
- package/edition/develop-seal.mjs +39 -25
- package/edition/dist-check.mjs +1 -1
- package/edition/edition-artifact.mjs +79 -18
- package/edition/edition-biome-manifests.mjs +2 -3
- package/edition/edition-chart-set.mjs +59 -6
- package/edition/edition-config.mjs +45 -21
- package/edition/edition-constants.mjs +10 -4
- package/edition/edition-contract-parse.mjs +52 -0
- package/edition/edition-contract.json +21 -5
- package/edition/edition-workspace.mjs +23 -9
- package/edition/evidence-checkout.mjs +22 -1
- package/edition/evidence-trust-policy.mjs +142 -78
- package/edition/external-source-walk.mjs +48 -61
- package/edition/git-source-auth.mjs +104 -25
- package/edition/image-delivery-entitlement-descriptor.mjs +106 -0
- package/edition/image-evidence.mjs +21 -3
- package/edition/kernel-contract-authority.mjs +23 -1
- package/edition/lib.mjs +16 -24
- package/edition/oras.mjs +1 -1
- package/edition/pin-source.mjs +6 -1
- package/edition/produce-image-delivery-entitlement-evidence.mjs +12 -12
- package/edition/registry-credentials.mjs +11 -1
- package/edition/release-channel-guard.mjs +11 -1
- package/edition/release-edition-artifact.mjs +5 -6
- package/edition/resolve-chart-set.mjs +50 -30
- package/edition/resolve-customer-edition.mjs +63 -7
- package/edition/resolve-distribution.mjs +1 -1
- package/edition/resolve-edition.mjs +12 -11
- package/edition/resolve-images.mjs +36 -15
- package/edition/seal-image-digests.mjs +31 -7
- package/edition/source-closure.mjs +1 -2
- package/edition/trust-policy-arming-verb.mjs +68 -0
- package/edition/verify-image-evidence.mjs +40 -12
- package/package.json +3 -3
|
@@ -49,6 +49,11 @@ import {
|
|
|
49
49
|
trustPolicyDigest,
|
|
50
50
|
verifierDigests,
|
|
51
51
|
} from './evidence-trust-pin.mjs';
|
|
52
|
+
import {
|
|
53
|
+
assertEntitlementDescriptorStates,
|
|
54
|
+
entitlementEvidenceRoot,
|
|
55
|
+
parseEntitlementDescriptorDocument,
|
|
56
|
+
} from './image-delivery-entitlement-descriptor.mjs';
|
|
52
57
|
import { verifyAndAdvanceReplayState } from './image-evidence-replay-state.mjs';
|
|
53
58
|
import {
|
|
54
59
|
readCanonicalJsonFromRoot,
|
|
@@ -64,13 +69,14 @@ import { loadVerifierKernelSchemas } from './verifier-kernel-schemas.mjs';
|
|
|
64
69
|
const USAGE =
|
|
65
70
|
'usage: verify-image-evidence <distributionId> --evidence-root <dir> --descriptor <absolute-path> --state <absolute-path> ' +
|
|
66
71
|
'--cosign <absolute-path> --git <absolute-path> [--evidence-set <relative-path>] [--json] ' +
|
|
67
|
-
'[--entitlement <relative-path> --customer <id> --mode <mode> [--target-registry <registry>]] ' +
|
|
72
|
+
'[--entitlement <relative-path> --entitlement-workflow-sha <40-hex git sha> --customer <id> --mode <mode> [--target-registry <registry>]] ' +
|
|
68
73
|
'--data-root <dir> --editions-root <dir> --kernel <dir>';
|
|
69
74
|
// The edition channel -> the kernel's evidence channel, stated once and explicitly.
|
|
70
75
|
const EVIDENCE_CHANNEL_OF_EDITION_CHANNEL = Object.freeze({
|
|
71
76
|
[EditionChannel.Release]: 'release',
|
|
72
77
|
[EditionChannel.Develop]: 'develop',
|
|
73
78
|
});
|
|
79
|
+
const GIT_COMMIT_SHA = /^[a-f0-9]{40}$/;
|
|
74
80
|
const DATA_ROOT_FILES = Object.freeze(['edition-workspace.json', 'runtime-image-source-index.json']);
|
|
75
81
|
|
|
76
82
|
function requireOptionValue(args, index, flag) {
|
|
@@ -101,6 +107,7 @@ function parseArgs(args) {
|
|
|
101
107
|
cosignBinary: null,
|
|
102
108
|
gitBinary: null,
|
|
103
109
|
entitlementDescriptorPath: null,
|
|
110
|
+
entitlementWorkflowSha: null,
|
|
104
111
|
customerId: null,
|
|
105
112
|
mode: null,
|
|
106
113
|
targetRegistry: null,
|
|
@@ -118,6 +125,7 @@ function parseArgs(args) {
|
|
|
118
125
|
else if (flag === '--cosign') {options.cosignBinary = value;}
|
|
119
126
|
else if (flag === '--git') {options.gitBinary = value;}
|
|
120
127
|
else if (flag === '--entitlement') {options.entitlementDescriptorPath = value;}
|
|
128
|
+
else if (flag === '--entitlement-workflow-sha') {options.entitlementWorkflowSha = value;}
|
|
121
129
|
else if (flag === '--customer') {options.customerId = value;}
|
|
122
130
|
else if (flag === '--mode') {options.mode = value;}
|
|
123
131
|
else if (flag === '--target-registry') {options.targetRegistry = value;}
|
|
@@ -137,9 +145,12 @@ function parseArgs(args) {
|
|
|
137
145
|
}
|
|
138
146
|
}
|
|
139
147
|
// An entitlement is verified whole or not at all: the descriptor names the
|
|
140
|
-
// signed statement,
|
|
148
|
+
// signed statement, the workflow SHA is the exact commit its certificate is
|
|
149
|
+
// held to (stated by the caller, never read from the evidence), and the
|
|
150
|
+
// customer and mode are what it must be bound to.
|
|
141
151
|
const entitlementFlags = [
|
|
142
152
|
['--entitlement', options.entitlementDescriptorPath],
|
|
153
|
+
['--entitlement-workflow-sha', options.entitlementWorkflowSha],
|
|
143
154
|
['--customer', options.customerId],
|
|
144
155
|
['--mode', options.mode],
|
|
145
156
|
];
|
|
@@ -150,7 +161,10 @@ function parseArgs(args) {
|
|
|
150
161
|
);
|
|
151
162
|
}
|
|
152
163
|
if (stated.length === 0 && options.targetRegistry !== null) {
|
|
153
|
-
throw new Error('--target-registry needs --entitlement, --customer and --mode');
|
|
164
|
+
throw new Error('--target-registry needs --entitlement, --entitlement-workflow-sha, --customer and --mode');
|
|
165
|
+
}
|
|
166
|
+
if (options.entitlementWorkflowSha !== null && !GIT_COMMIT_SHA.test(options.entitlementWorkflowSha)) {
|
|
167
|
+
throw new Error('--entitlement-workflow-sha must be a 40-character lowercase hexadecimal git commit SHA');
|
|
154
168
|
}
|
|
155
169
|
if (options.entitlementDescriptorPath !== null && isAbsolute(options.entitlementDescriptorPath)) {
|
|
156
170
|
throw new Error('--entitlement must be an evidence-root-relative path');
|
|
@@ -185,6 +199,7 @@ export const EDITION_EVIDENCE_VERIFICATION_SCHEMA = 'xema.edition-evidence-verif
|
|
|
185
199
|
* What `--json` prints once the evidence is verified: the channel it was verified
|
|
186
200
|
* on, the release sequence it proved, and the statementDigest (the digest of the verified in-toto statement, not of the image) of every statement verified
|
|
187
201
|
* (producers by subject, then completeness, then the entitlement if one was asked for).
|
|
202
|
+
* `entitlementDescriptor` is the Sigstore evidence descriptor `entitlement.json` holds.
|
|
188
203
|
*/
|
|
189
204
|
export function evidenceVerificationDocument({ distributionId, channel, evidenceSet, verified, entitlementDescriptor }) {
|
|
190
205
|
const producers = evidenceSet.producerEvidence
|
|
@@ -350,19 +365,32 @@ export async function verifyEvidence({ argv, env, bundlePath }) {
|
|
|
350
365
|
cosignBinary: options.cosignBinary,
|
|
351
366
|
schemas,
|
|
352
367
|
});
|
|
353
|
-
const
|
|
368
|
+
const entitlement =
|
|
354
369
|
options.entitlementDescriptorPath === null
|
|
355
370
|
? null
|
|
356
|
-
:
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
371
|
+
: parseEntitlementDescriptorDocument(
|
|
372
|
+
readCanonicalJsonFromRoot(
|
|
373
|
+
evidenceRoot,
|
|
374
|
+
options.entitlementDescriptorPath,
|
|
375
|
+
'delivery entitlement descriptor',
|
|
376
|
+
),
|
|
377
|
+
schemas,
|
|
360
378
|
);
|
|
379
|
+
if (entitlement !== null) {
|
|
380
|
+
assertEntitlementDescriptorStates(entitlement, {
|
|
381
|
+
distributionId: options.distributionId,
|
|
382
|
+
customerId: options.customerId,
|
|
383
|
+
mode: options.mode,
|
|
384
|
+
targetRegistry: options.targetRegistry,
|
|
385
|
+
distributionStatementDigest: result.completenessStatementDigest,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
const entitlementDescriptor = entitlement === null ? null : entitlement.evidence;
|
|
361
389
|
const entitlementStatement =
|
|
362
390
|
entitlementDescriptor === null
|
|
363
391
|
? null
|
|
364
392
|
: await verifyImageDeliveryEntitlement({
|
|
365
|
-
evidenceRoot,
|
|
393
|
+
evidenceRoot: entitlementEvidenceRoot(evidenceRoot, options.entitlementDescriptorPath),
|
|
366
394
|
descriptor: entitlementDescriptor,
|
|
367
395
|
policy: anchors.policy,
|
|
368
396
|
policyRoot: dataRoot(),
|
|
@@ -373,9 +401,9 @@ export async function verifyEvidence({ argv, env, bundlePath }) {
|
|
|
373
401
|
mode: options.mode,
|
|
374
402
|
targetRegistry: options.targetRegistry,
|
|
375
403
|
now: new Date(),
|
|
376
|
-
// The entitlement predicate carries no producer run
|
|
377
|
-
//
|
|
378
|
-
expectedWorkflowSha:
|
|
404
|
+
// The entitlement predicate carries no producer run: the commit
|
|
405
|
+
// its certificate is held to is the caller's statement.
|
|
406
|
+
expectedWorkflowSha: options.entitlementWorkflowSha,
|
|
379
407
|
// A nonce spent by a producer or completeness statement of
|
|
380
408
|
// this release cannot be reused by its entitlement.
|
|
381
409
|
consumedNonces: result.verifiedNonces,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/xema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/xema-dev/xema-cli.git",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"@nestjs/platform-express": "^11.1.28",
|
|
52
52
|
"@xemahq/biome-sdk": "^18.1.0",
|
|
53
53
|
"@xemahq/biome-supply-chain": "^0.5.0",
|
|
54
|
+
"@xemahq/distribution-source-hash": "^0.3.0",
|
|
54
55
|
"@xemahq/dsl": "^0.23.0",
|
|
55
56
|
"@xemahq/identity-client": "^0.16.0",
|
|
56
57
|
"@xemahq/contracts": "^0.76.0",
|
|
@@ -68,7 +69,6 @@
|
|
|
68
69
|
"@types/jest": "^30.0.0",
|
|
69
70
|
"@types/node": "25.2.3",
|
|
70
71
|
"@xemahq/biome-host-api-client": "^0.3.31",
|
|
71
|
-
"@xemahq/distribution-source-hash": "^0.3.0",
|
|
72
72
|
"@xemahq/eslint-config": "^0.9.2",
|
|
73
73
|
"esbuild": "0.28.2",
|
|
74
74
|
"eslint": "^9.39.4",
|
|
@@ -92,6 +92,6 @@
|
|
|
92
92
|
"typecheck": "tsc --noEmit"
|
|
93
93
|
},
|
|
94
94
|
"xemaRelease": {
|
|
95
|
-
"sourceDigest": "sha256:
|
|
95
|
+
"sourceDigest": "sha256:a0dc6a3fdb7cce15b031dcd04476f19924d13d36924070b1527af1fa613b258e"
|
|
96
96
|
}
|
|
97
97
|
}
|