@xemahq/xema 0.52.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 +1013 -870
- package/dist/edition/verify-image-evidence.bundle.provenance.json +501 -495
- 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 +8 -2
- package/edition/evidence-input-mode.mjs +4 -22
- 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/operation-requirements.mjs +11 -0
- package/edition/platform-service-class.mjs +4 -2
- 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
|
@@ -1787,11 +1787,15 @@ export function supplementalSourcesFor(runtimeSourceIndex) {
|
|
|
1787
1787
|
* of one (a customer's own rows, merged with the catalogue's) parses the lock
|
|
1788
1788
|
* it completes. `resolveImages` is these rows parsed as the whole lock.
|
|
1789
1789
|
*/
|
|
1790
|
-
export async function resolveImageRows(id, { inputs, lock, onSubjectHashed } = {}) {
|
|
1790
|
+
export async function resolveImageRows(id, { inputs, lock, onSubjectHashed, recordedImages } = {}) {
|
|
1791
1791
|
assertCanonicalDistributionId(id);
|
|
1792
1792
|
if ((inputs === undefined) !== (lock === undefined)) {
|
|
1793
1793
|
throw new Error('resolveImages takes the snapshot `inputs` and its distribution `lock` together, or neither');
|
|
1794
1794
|
}
|
|
1795
|
+
// A build record (images-from-record.mjs) replaces the hashing on the snapshot lane only, and never beside a probe.
|
|
1796
|
+
if (recordedImages !== undefined && (inputs === undefined || onSubjectHashed !== undefined)) {
|
|
1797
|
+
throw new Error('resolveImages takes recorded images only on the snapshot lane, and never with onSubjectHashed');
|
|
1798
|
+
}
|
|
1795
1799
|
const schemas = await loadKernelDistributionSchemas();
|
|
1796
1800
|
const {
|
|
1797
1801
|
lock: distributionLock,
|
|
@@ -1897,7 +1901,8 @@ export async function resolveImageRows(id, { inputs, lock, onSubjectHashed } = {
|
|
|
1897
1901
|
const { sourceManifestPath: ignoredSourceManifestPath, ...lockedSubject } =
|
|
1898
1902
|
subject;
|
|
1899
1903
|
void ignoredSourceManifestPath;
|
|
1900
|
-
|
|
1904
|
+
// With a build record the content hash and source commit are the record's, carried and never recomputed.
|
|
1905
|
+
const hashed = recordedImages === undefined ? {
|
|
1901
1906
|
...lockedSubject,
|
|
1902
1907
|
sourceCommit,
|
|
1903
1908
|
contentHash: exactImageBuildInputHash(
|
|
@@ -1912,7 +1917,7 @@ export async function resolveImageRows(id, { inputs, lock, onSubjectHashed } = {
|
|
|
1912
1917
|
},
|
|
1913
1918
|
imageInputSourceHashAlgorithm(),
|
|
1914
1919
|
),
|
|
1915
|
-
};
|
|
1920
|
+
} : { ...lockedSubject, ...recordedImages.take({ ...lockedSubject, sourceCommit }) };
|
|
1916
1921
|
subjects.push(hashed);
|
|
1917
1922
|
// The hash is the last thing a registry probe waits for: hand the subject
|
|
1918
1923
|
// over now, and let the event loop run so the probes of the subjects
|
|
@@ -1922,6 +1927,8 @@ export async function resolveImageRows(id, { inputs, lock, onSubjectHashed } = {
|
|
|
1922
1927
|
await yieldToEventLoop();
|
|
1923
1928
|
}
|
|
1924
1929
|
}
|
|
1930
|
+
// Every subject missing from, contradicted by or extra in the build record, refused at once.
|
|
1931
|
+
recordedImages?.settle();
|
|
1925
1932
|
// Release lane only: a develop snapshot or customer overlay is not covered by
|
|
1926
1933
|
// the committed ledger.
|
|
1927
1934
|
if (inputs === undefined) {
|
|
@@ -1962,8 +1969,8 @@ export async function resolveImageRows(id, { inputs, lock, onSubjectHashed } = {
|
|
|
1962
1969
|
}
|
|
1963
1970
|
|
|
1964
1971
|
/** One edition's COMPLETE image lock: its rows, parsed and validated as the kernel's image lock. */
|
|
1965
|
-
export async function resolveImages(id, { inputs, lock, onSubjectHashed } = {}) {
|
|
1966
|
-
const { subjects, thirdPartySubjects, platformServiceBindings, webBiomes, contractAuthority, commits } = await resolveImageRows(id, { inputs, lock, onSubjectHashed });
|
|
1972
|
+
export async function resolveImages(id, { inputs, lock, onSubjectHashed, recordedImages } = {}) {
|
|
1973
|
+
const { subjects, thirdPartySubjects, platformServiceBindings, webBiomes, contractAuthority, commits } = await resolveImageRows(id, { inputs, lock, onSubjectHashed, recordedImages });
|
|
1967
1974
|
const schemas = await loadKernelDistributionSchemas();
|
|
1968
1975
|
const imageLock = validateImmutableImageLock(
|
|
1969
1976
|
schemas.parseImageLock({
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shallow git core every source checkout of the edition library runs: a checkout of exactly one commit
|
|
3
|
+
* and a depth-1 fetch of one more commit into it. `runGit(args, gitEnv)` spawns git; the caller owns the
|
|
4
|
+
* credential env (git-source-auth.mjs `withSourceGitEnv`) and verifies the result.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** `target` becomes a detached checkout of `commit` from `url`, fetched at depth 1. */
|
|
8
|
+
export function shallowCheckout({ runGit, gitEnv, target, url, commit }) {
|
|
9
|
+
runGit(['init', '--quiet', target], gitEnv);
|
|
10
|
+
runGit(['-C', target, 'remote', 'add', 'origin', url], gitEnv);
|
|
11
|
+
shallowFetch({ runGit, gitEnv, target, commit });
|
|
12
|
+
runGit(['-C', target, 'checkout', '--quiet', '--detach', commit], gitEnv);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** One more commit into an existing checkout, from its origin, at depth 1. */
|
|
16
|
+
export function shallowFetch({ runGit, gitEnv, target, commit }) {
|
|
17
|
+
runGit(['-C', target, 'fetch', '--quiet', '--depth=1', 'origin', commit], gitEnv);
|
|
18
|
+
}
|
|
@@ -106,13 +106,26 @@ export class RetiredFirstPartySourceShapeError extends Error {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Where a first-party source's images come from on the everyday lane: built by the job in the aggregator workspace,
|
|
111
|
+
* or a satellite producer's own signed develop digest (a source outside the workspace, such as
|
|
112
|
+
* submodules/xema-host-web). `--images-from` admits a record entry only from the list its source's origin names.
|
|
113
|
+
*/
|
|
114
|
+
export const FirstPartyImageOrigin = Object.freeze({
|
|
115
|
+
Workspace: 'workspace',
|
|
116
|
+
Satellite: 'satellite',
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const IMAGE_ORIGINS = Object.values(FirstPartyImageOrigin);
|
|
120
|
+
|
|
109
121
|
/**
|
|
110
122
|
* `firstPartySources`: every first-party repository, keyed by its source
|
|
111
123
|
* checkout handle, with its declared source id (the identity a runtime subject
|
|
112
124
|
* is named after) and its repository URL (where it lives: the develop graph
|
|
113
125
|
* resolves its head there, and a release pin must name the same URL). The URL
|
|
114
126
|
* is checked canonical and under `sourceRepositoryUrlPrefix` with the whole
|
|
115
|
-
* config (edition-config.mjs).
|
|
127
|
+
* config (edition-config.mjs). `imageOrigin` (FirstPartyImageOrigin) is optional
|
|
128
|
+
* here and has no default: `--images-from` refuses a source that does not declare it.
|
|
116
129
|
*/
|
|
117
130
|
export function parseFirstPartySources(value) {
|
|
118
131
|
const where = '"firstPartySources"';
|
|
@@ -123,11 +136,18 @@ export function parseFirstPartySources(value) {
|
|
|
123
136
|
repoHandle(repo, `${where} key`);
|
|
124
137
|
if (typeof entry === 'string') {throw new RetiredFirstPartySourceShapeError(repo, entry);}
|
|
125
138
|
const at = `${where}["${repo}"]`;
|
|
126
|
-
exactObject(entry, at, ['sourceId', 'repositoryUrl']);
|
|
139
|
+
exactObject(entry, at, ['sourceId', 'repositoryUrl'], ['imageOrigin']);
|
|
127
140
|
if (typeof entry.sourceId !== 'string' || !SOURCE_ID.test(entry.sourceId)) {
|
|
128
141
|
fail(`${at}.sourceId`, `must be a lowercase kebab-case source id; got ${JSON.stringify(entry.sourceId)}`);
|
|
129
142
|
}
|
|
130
|
-
|
|
143
|
+
if (Object.hasOwn(entry, 'imageOrigin') && !IMAGE_ORIGINS.includes(entry.imageOrigin)) {
|
|
144
|
+
fail(`${at}.imageOrigin`, `must be one of ${IMAGE_ORIGINS.join(', ')}; got ${JSON.stringify(entry.imageOrigin)}`);
|
|
145
|
+
}
|
|
146
|
+
return [repo, Object.freeze({
|
|
147
|
+
sourceId: entry.sourceId,
|
|
148
|
+
repositoryUrl: text(entry.repositoryUrl, `${at}.repositoryUrl`),
|
|
149
|
+
...(Object.hasOwn(entry, 'imageOrigin') ? { imageOrigin: entry.imageOrigin } : {}),
|
|
150
|
+
})];
|
|
131
151
|
});
|
|
132
152
|
uniqueBy(entries, `${where} sourceId`, ([, entry]) => entry.sourceId);
|
|
133
153
|
uniqueBy(entries, `${where} repositoryUrl`, ([, entry]) => entry.repositoryUrl);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/xema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/xema-dev/xema-cli.git",
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"types": "./dist/publisher.d.ts",
|
|
29
29
|
"require": "./dist/publisher.js",
|
|
30
30
|
"default": "./dist/publisher.js"
|
|
31
|
+
},
|
|
32
|
+
"./candidate-edition": {
|
|
33
|
+
"import": "./edition/candidate-edition.mjs",
|
|
34
|
+
"default": "./edition/candidate-edition.mjs"
|
|
31
35
|
}
|
|
32
36
|
},
|
|
33
37
|
"bin": {
|
|
@@ -57,7 +61,7 @@
|
|
|
57
61
|
"@xemahq/distribution-source-hash": "^0.2.2",
|
|
58
62
|
"@xemahq/dsl": "^0.28.0",
|
|
59
63
|
"@xemahq/identity-client": "^0.36.0",
|
|
60
|
-
"@xemahq/contracts": "^0.
|
|
64
|
+
"@xemahq/contracts": "^0.117.0",
|
|
61
65
|
"@xemahq/kernel-state-runtime": "^0.8.0",
|
|
62
66
|
"@xemahq/license-verifier": "^0.2.0",
|
|
63
67
|
"@xemahq/release-policy": "^17.6.0",
|
|
@@ -96,6 +100,6 @@
|
|
|
96
100
|
"typecheck": "tsc --noEmit"
|
|
97
101
|
},
|
|
98
102
|
"xemaRelease": {
|
|
99
|
-
"sourceDigest": "sha256:
|
|
103
|
+
"sourceDigest": "sha256:7bcf18b69778e4e380b22bf9c301cf08ea6234a10c98ec06940abdde0f8920c1"
|
|
100
104
|
}
|
|
101
105
|
}
|