@xemahq/xema 0.33.2 → 0.33.4
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 +12 -17
- package/dist/edition/verify-image-evidence.bundle.provenance.json +47 -41
- package/dist/runtime/runner/chart-set-lock.d.ts +0 -3
- package/dist/runtime/runner/chart-set-lock.d.ts.map +1 -1
- package/dist/runtime/runner/chart-set-lock.js +3 -25
- package/dist/runtime/runner/chart-set-lock.js.map +1 -1
- package/edition/chart-set-source-commit.mjs +2 -7
- package/edition/checkout-indexed-source-repositories.mjs +67 -0
- package/edition/cross-repo-build-inputs.mjs +158 -0
- package/edition/develop-chart-set.mjs +61 -0
- package/edition/develop-edition-resolve.mjs +6 -7
- package/edition/dist-check.mjs +1 -2
- package/edition/edition-artifact.mjs +1 -1
- package/edition/edition-chart-set.mjs +11 -53
- package/edition/git-json.mjs +54 -0
- package/edition/lib.mjs +3 -165
- package/edition/release-channel-guard.mjs +3 -4
- package/edition/release-edition-artifact.mjs +1 -1
- package/edition/resolve-chart-set.mjs +7 -69
- package/edition/resolve-customer-edition.mjs +1 -1
- package/edition/resolve-images.mjs +1 -3
- package/package.json +2 -2
|
@@ -17,7 +17,7 @@ import { join, resolve } from 'node:path';
|
|
|
17
17
|
|
|
18
18
|
import { isDevelopImageRef } from './develop-image-coordinate.mjs';
|
|
19
19
|
import { EDITION_CHART_SET_FILE, assertRosteredChartSetLock } from './edition-chart-set.mjs';
|
|
20
|
-
import {
|
|
20
|
+
import { EditionLockFile } from './edition-constants.mjs';
|
|
21
21
|
import { isEntryModule } from './edition-workspace.mjs';
|
|
22
22
|
|
|
23
23
|
/** Throws when `value` (a parsed JSON document) names a develop image repository. `where` names it in the refusal. */
|
|
@@ -30,10 +30,9 @@ export function assertReleaseContent(value, where) {
|
|
|
30
30
|
'a release lock names release repositories only',
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
|
-
// A chart-set lock (one with a roster of publishers) carries
|
|
34
|
-
// coordinates only: a develop chart set copied into a release is refused.
|
|
33
|
+
// A chart-set lock (one with a roster of publishers) carries content coordinates only.
|
|
35
34
|
if (Array.isArray(value.publishers)) {
|
|
36
|
-
assertRosteredChartSetLock(value, where
|
|
35
|
+
assertRosteredChartSetLock(value, where);
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
|
|
@@ -123,7 +123,7 @@ export async function readCommittedEdition(id, root = editionsRoot()) {
|
|
|
123
123
|
distributionLock,
|
|
124
124
|
imageLock: read(EditionLockFile.Images),
|
|
125
125
|
authorizationLock: read(EditionLockFile.Authorization),
|
|
126
|
-
chartSetLock: assertRosteredChartSetLock(read(EditionLockFile.ChartSet), join(dir, EditionLockFile.ChartSet)
|
|
126
|
+
chartSetLock: assertRosteredChartSetLock(read(EditionLockFile.ChartSet), join(dir, EditionLockFile.ChartSet)),
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -55,27 +55,21 @@
|
|
|
55
55
|
// shape this plane has been bitten by: a claim that outlives its evidence.
|
|
56
56
|
|
|
57
57
|
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
58
|
-
import {
|
|
58
|
+
import { join } from 'node:path';
|
|
59
59
|
|
|
60
|
-
import { EditionChannel } from './edition-channel.mjs';
|
|
61
60
|
import {
|
|
62
61
|
EDITION_CHART_SET_FILE,
|
|
63
62
|
CHART_SET_LOCK_SCHEMA_VERSION,
|
|
64
|
-
DEVELOP_CHART_VERSION_PREFIX,
|
|
65
63
|
EditionChartSetCheck,
|
|
66
64
|
OCI_DIGEST_PATTERN,
|
|
67
65
|
assertRosteredChartSetLock,
|
|
68
66
|
checkEditionChartSet,
|
|
69
|
-
DEVELOP_CHART_SHA_LENGTH,
|
|
70
|
-
hasDevelopChartVersionPrefix,
|
|
71
|
-
isDevelopChartVersion,
|
|
72
67
|
writeEditionChartSet,
|
|
73
68
|
} from './edition-chart-set.mjs';
|
|
74
69
|
import { vendorChartSetConfig } from './edition-config.mjs';
|
|
75
70
|
import { WorkspaceRoot, configureEditionWorkspaceFromProcess, dataRoot, editionsRoot, isEntryModule } from './edition-workspace.mjs';
|
|
76
71
|
import { serializeJson } from './lib.mjs';
|
|
77
72
|
import { OrasRegistry } from './oras.mjs';
|
|
78
|
-
import { deployPinKey } from './pin-source.mjs';
|
|
79
73
|
import {
|
|
80
74
|
loadRegistryCredentialDeclarations,
|
|
81
75
|
resolveRegistryCredential,
|
|
@@ -129,11 +123,8 @@ export function isVersionTag(tag) {
|
|
|
129
123
|
* last: guessing an order for a coordinate whose age is unknown is how a stale
|
|
130
124
|
* set gets pinned as current.
|
|
131
125
|
*/
|
|
132
|
-
export function selectNewestIndex(
|
|
133
|
-
if (!Array.isArray(
|
|
134
|
-
// Anything with the develop prefix (`0.0.0-dev.`) is a frozen xema-deploy
|
|
135
|
-
// snapshot or a malformed develop version, never a release index: it is not a candidate for the release pin.
|
|
136
|
-
const candidates = allCandidates.filter((c) => !hasDevelopChartVersionPrefix(c.tag));
|
|
126
|
+
export function selectNewestIndex(candidates) {
|
|
127
|
+
if (!Array.isArray(candidates)) {return null;}
|
|
137
128
|
if (candidates.length === 0) {return null;}
|
|
138
129
|
const undated = candidates.filter((c) => !c.createdAt);
|
|
139
130
|
if (undated.length > 0) {
|
|
@@ -155,8 +146,7 @@ export const INDEX_ROSTER_ANNOTATION = 'xema.dev/chart-set-charts';
|
|
|
155
146
|
|
|
156
147
|
/**
|
|
157
148
|
* The lock for `publishers`: each publisher's index version, the manifest digest
|
|
158
|
-
* the registry served for that index (`indexDigestsByIndex
|
|
159
|
-
* snapshot, which has no index chart), and its sealed roster.
|
|
149
|
+
* the registry served for that index (`indexDigestsByIndex`), and its sealed roster.
|
|
160
150
|
*/
|
|
161
151
|
export function buildLock(versionsByIndex, rostersByIndex, indexDigestsByIndex, publishers = chartSetPublishers()) {
|
|
162
152
|
// Every publisher's VERSION first: a pin that resolved nothing for one half is
|
|
@@ -193,9 +183,8 @@ export function buildLock(versionsByIndex, rostersByIndex, indexDigestsByIndex,
|
|
|
193
183
|
}
|
|
194
184
|
// The digest the registry served for the index manifest the roster was read from.
|
|
195
185
|
const indexDigest = indexDigestsByIndex?.[publisher.index];
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
throw new Error(`no index manifest digest was read for '${publisher.index}@${version}' (got ${JSON.stringify(indexDigest ?? null)}; a release index needs sha256:<64 hex>, a develop snapshot null)`);
|
|
186
|
+
if (!DIGEST_PATTERN.test(String(indexDigest))) {
|
|
187
|
+
throw new Error(`no index manifest digest was read for '${publisher.index}@${version}' (got ${JSON.stringify(indexDigest ?? null)}; a release index needs sha256:<64 hex>)`);
|
|
199
188
|
}
|
|
200
189
|
return { ...publisher, version, indexDigest, charts };
|
|
201
190
|
}),
|
|
@@ -277,63 +266,12 @@ function editionDirs() {
|
|
|
277
266
|
.sort();
|
|
278
267
|
}
|
|
279
268
|
|
|
280
|
-
const SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
281
|
-
|
|
282
|
-
/** The develop chart version xema-deploy publishes for a frozen SHA: `0.0.0-dev.<sha12>`, also the OCI tag. */
|
|
283
|
-
export const developChartVersion = (sha) => `${DEVELOP_CHART_VERSION_PREFIX}${sha.slice(0, DEVELOP_CHART_SHA_LENGTH)}`;
|
|
284
|
-
|
|
285
|
-
/** Every chart (a directory with a Chart.yaml, library charts included) of an xema-deploy checkout, sorted. */
|
|
286
|
-
function deployChartNames(xemaDeployDir) {
|
|
287
|
-
const chartsDir = join(xemaDeployDir, 'charts');
|
|
288
|
-
if (!existsSync(chartsDir)) {throw new Error(`${xemaDeployDir} has no charts/ directory`);}
|
|
289
|
-
return readdirSync(chartsDir, { withFileTypes: true })
|
|
290
|
-
.filter((entry) => entry.isDirectory() && existsSync(join(chartsDir, entry.name, 'Chart.yaml')))
|
|
291
|
-
.map((entry) => entry.name)
|
|
292
|
-
.sort();
|
|
293
|
-
}
|
|
294
|
-
|
|
295
269
|
/** The registry client for the chart registry, with the data root's declared credential. */
|
|
296
270
|
export function chartRegistryClient() {
|
|
297
271
|
const credential = resolveRegistryCredential({ authority: registryAuthority(), declarations: loadRegistryCredentialDeclarations() });
|
|
298
272
|
return new OrasRegistry({ credential });
|
|
299
273
|
}
|
|
300
274
|
|
|
301
|
-
/** The manifest digest the chart registry serves for `<chart>:<version>`. */
|
|
302
|
-
const registryManifestDigest = (client) => async (name, version) =>
|
|
303
|
-
(await client.getManifestByTag(registryRepository(name), version)).digest;
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* The develop chart-set lock: the SAME rostered lock a release pins, over the
|
|
307
|
-
* charts xema-deploy publishes for the frozen SHA. The deploy publisher (the
|
|
308
|
-
* workspace publisher whose repository is the deploy pin role's) publishes every
|
|
309
|
-
* chart directory of its tree at `0.0.0-dev.<sha12>`; the roster records each
|
|
310
|
-
* chart's registry manifest digest, so a consumer pulls by digest exactly as it
|
|
311
|
-
* does for a release. A chart the registry does not serve is refused by name.
|
|
312
|
-
* `lookup(name, version)` defaults to the chart registry and returns the digest.
|
|
313
|
-
*/
|
|
314
|
-
export async function resolveDevelopChartSet({ xemaDeployDir, xemaDeploySha, lookup }) {
|
|
315
|
-
if (!SHA_PATTERN.test(xemaDeploySha ?? '')) {
|
|
316
|
-
throw new Error(`the deploy checkout SHA is not a 40-hex commit: ${JSON.stringify(xemaDeploySha)}`);
|
|
317
|
-
}
|
|
318
|
-
const names = deployChartNames(xemaDeployDir);
|
|
319
|
-
if (names.length === 0) {throw new Error(`the deploy checkout at ${xemaDeploySha} has no chart (charts/<name>/Chart.yaml)`);}
|
|
320
|
-
const deployRepo = basename(deployPinKey());
|
|
321
|
-
const publishers = chartSetPublishers().filter((publisher) => basename(publisher.repo) === deployRepo);
|
|
322
|
-
if (publishers.length !== 1) {
|
|
323
|
-
throw new Error(
|
|
324
|
-
`${publishers.length} chart publishers have repository ${deployRepo} (the deploy pin role); exactly one must, ` +
|
|
325
|
-
'since it is the publisher whose develop charts this lock pins',
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
const version = developChartVersion(xemaDeploySha);
|
|
329
|
-
const digestOf = lookup ?? registryManifestDigest(chartRegistryClient());
|
|
330
|
-
const roster = Object.fromEntries(names.map((name) => [name, { version }]));
|
|
331
|
-
const sealed = await sealRoster(roster, digestOf, `${publishers[0].index}@${version}`);
|
|
332
|
-
// A develop snapshot has no index chart: its roster is the deploy checkout's chart directories.
|
|
333
|
-
const lock = buildLock({ [publishers[0].index]: version }, { [publishers[0].index]: sealed }, { [publishers[0].index]: null }, publishers);
|
|
334
|
-
return assertRosteredChartSetLock(lock, EDITION_CHART_SET_FILE, EditionChannel.Develop);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
275
|
export function readLock(path = chartSetLockPath()) {
|
|
338
276
|
try {
|
|
339
277
|
return JSON.parse(readFileSync(path, 'utf8'));
|
|
@@ -395,7 +333,7 @@ async function main(argv) {
|
|
|
395
333
|
const check = argv.includes('--check');
|
|
396
334
|
const { versionsByIndex, rostersByIndex, indexDigestsByIndex } = await resolveFromRegistry();
|
|
397
335
|
const next = buildLock(versionsByIndex, rostersByIndex, indexDigestsByIndex);
|
|
398
|
-
assertRosteredChartSetLock(next, CHART_SET_LOCK_FILE
|
|
336
|
+
assertRosteredChartSetLock(next, CHART_SET_LOCK_FILE);
|
|
399
337
|
const pinText = serializeJson(next);
|
|
400
338
|
const current = readLock();
|
|
401
339
|
// The pin AND every edition's copy of it: one writer, one run, so the N copies
|
|
@@ -326,7 +326,7 @@ export async function resolveCustomerEdition(request) {
|
|
|
326
326
|
const imageLock = await resolveCustomerImages({ id, catalogue, lock, composed, schemas, inputs, sealOwn: request.sealOwn });
|
|
327
327
|
// The chart-set is copied whole, so it carries the coordinates of the channel it was published on:
|
|
328
328
|
// the edition being written states its channel, and a chart-set of the other one is refused here.
|
|
329
|
-
const chartSetLock = assertRosteredChartSetLock(catalogue.chartSet, `the catalogue's chart-set of "${catalogue.offeringId}"
|
|
329
|
+
const chartSetLock = assertRosteredChartSetLock(catalogue.chartSet, `the catalogue's chart-set of "${catalogue.offeringId}"`);
|
|
330
330
|
return { id, distributionLock: lock, imageLock, authorizationLock, chartSetLock };
|
|
331
331
|
}
|
|
332
332
|
|
|
@@ -38,6 +38,7 @@ import { join, relative, sep } from 'node:path';
|
|
|
38
38
|
|
|
39
39
|
import { assertBuildLedgerComplete } from './build-ledger-completeness.mjs';
|
|
40
40
|
import { BUILD_LEDGER_FILE, readBuildLedger } from './build-ledger.mjs';
|
|
41
|
+
import { CROSS_REPO_BUILD_INPUTS_PATH, crossRepoInputKey, resolveCrossRepoVendoredInputs } from './cross-repo-build-inputs.mjs';
|
|
41
42
|
import { resolveDispatchedRuntimeComponents } from './dispatched-runtime-components.mjs';
|
|
42
43
|
import {
|
|
43
44
|
assertCanonicalDistributionId,
|
|
@@ -53,15 +54,12 @@ import {
|
|
|
53
54
|
} from './external-source-walk.mjs';
|
|
54
55
|
import { assertDeclaredSourceId, firstPartySourceId } from './first-party-source-ids.mjs';
|
|
55
56
|
import {
|
|
56
|
-
CROSS_REPO_BUILD_INPUTS_PATH,
|
|
57
57
|
compareStrings,
|
|
58
|
-
crossRepoInputKey,
|
|
59
58
|
hashImageBuildInputs,
|
|
60
59
|
imageInputSourceHashAlgorithm,
|
|
61
60
|
loadKernelDistributionSchemas,
|
|
62
61
|
parseResolvedDistributionLock,
|
|
63
62
|
readGitJsonAtCommit,
|
|
64
|
-
resolveCrossRepoVendoredInputs,
|
|
65
63
|
serializeJson,
|
|
66
64
|
sha256Hex,
|
|
67
65
|
validateImmutableDistributionLock,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/xema",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.4",
|
|
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:a8780b8b95054688b280033f5aec97bbdb0d4bc211513d09a992a3c025af653e"
|
|
96
96
|
}
|
|
97
97
|
}
|