@xemahq/xema 0.54.0 → 0.56.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 +1996 -1012
- package/dist/edition/verify-image-evidence.bundle.provenance.json +584 -500
- package/dist/runtime/lock-loader.d.ts +2 -1
- package/dist/runtime/lock-loader.d.ts.map +1 -1
- package/dist/runtime/lock-loader.js +15 -5
- package/dist/runtime/lock-loader.js.map +1 -1
- package/edition/README.md +8 -3
- package/edition/biome-content.mjs +4 -4
- package/edition/candidate-edition.mjs +8 -3
- package/edition/check-committed-image-evidence.mjs +44 -15
- package/edition/customer-edition-verbs.mjs +15 -4
- package/edition/develop-current-resolution.mjs +29 -0
- package/edition/develop-edition-resolve.mjs +18 -10
- package/edition/develop-edition.mjs +30 -9
- package/edition/develop-freeze.mjs +24 -1
- package/edition/develop-git-bundles.mjs +201 -0
- package/edition/develop-graph.mjs +5 -3
- package/edition/develop-image-probe.mjs +6 -4
- package/edition/develop-image-record.mjs +194 -0
- package/edition/develop-record-ancestry.mjs +23 -5
- package/edition/develop-select-records.mjs +29 -21
- package/edition/develop-selection-line.mjs +30 -0
- package/edition/develop-selection-pins.mjs +30 -0
- package/edition/dist-check.mjs +45 -9
- package/edition/distribution-evidence-set.mjs +14 -9
- package/edition/edition-image-seal.mjs +2 -1
- package/edition/edition-protocol.mjs +6 -20
- package/edition/external-source-walk.mjs +37 -15
- package/edition/image-evidence.mjs +6 -2
- package/edition/image-lock-service-rows.mjs +4 -4
- package/edition/image-subject-identity.mjs +24 -0
- package/edition/images-from-record.mjs +46 -110
- package/edition/lib.mjs +24 -26
- package/edition/locked-bundle-signer.mjs +52 -8
- package/edition/resolve-customer-edition.mjs +1 -1
- package/edition/resolve-distribution.mjs +84 -21
- package/edition/resolve-edition.mjs +2 -1
- package/edition/resolve-images.mjs +224 -12
- package/edition/seal-image-digests.mjs +24 -13
- package/edition/third-party-bundle-registry.mjs +73 -17
- package/edition/third-party-source-evidence.mjs +39 -14
- package/edition/third-party-source-writer.mjs +2 -18
- package/edition/trust-policy-arming.mjs +17 -6
- package/edition/verify-image-platforms.mjs +2 -0
- package/edition/workspace-sections.mjs +11 -1
- package/package.json +3 -3
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
// Every `bundleSource: {kind: 'oci'}` row of a lock (a biome's, or one of its host modules') states WHO signs its bundle:
|
|
4
4
|
// `bundleSigner: {policyId, signer}`, the kernel's `lockedBundleSignerOf` projection of ONE row of the data root's evidence
|
|
5
5
|
// trust policy. The row is selected, never defaulted:
|
|
6
|
-
// - a git-sourced row (one with a lock `source`) carries no OCI bundle
|
|
6
|
+
// - a git-sourced row (one with a lock `source`) carries no OCI bundle, and a lock stating one is refused, EXCEPT in a
|
|
7
|
+
// selection made for a vendor develop edition (`GitSourcedBundle.DevelopVerified`, XEMA-2456): there a git-sourced
|
|
8
|
+
// biome row may carry the bundle the develop resolve verified (`develop-git-bundles.mjs`), signed by the ONE
|
|
9
|
+
// `develop` row of the source's repository;
|
|
7
10
|
// - a third-party row (no `source`, `isThirdPartyOciRow`) by its pin (`third-party-source-pins.json`), whose `bundle.signerPolicyId` names an
|
|
8
11
|
// `oidc-certificate` row held to the checks `thirdPartySignerRow` makes;
|
|
9
12
|
// - a first-party row by the data root's `firstPartyBundleSigner.policyId`, a `public-key` row whose key is bound to
|
|
@@ -15,13 +18,15 @@
|
|
|
15
18
|
|
|
16
19
|
import { createRequire } from 'node:module';
|
|
17
20
|
|
|
21
|
+
import { canonicalPublicHttpsRepositoryUrl, repositoryOwnerName } from './canonical-repository-url.mjs';
|
|
18
22
|
import { KernelRefusalName, RefusalError, collectRefusals, isRefusal, joinRefusalMessages } from './collected-refusals.mjs';
|
|
23
|
+
import { EditionChannel } from './edition-channel.mjs';
|
|
19
24
|
import { editionWorkspaceConfig } from './edition-config.mjs';
|
|
20
25
|
import { assertKernelEditionProtocol } from './edition-protocol.mjs';
|
|
21
26
|
import { dataRoot, kernelDistPath, kernelPackageDir } from './edition-workspace.mjs';
|
|
22
27
|
import { loadPinnedDeclaredTrustPolicy } from './evidence-trust-pin.mjs';
|
|
23
28
|
import { loadTrustedThirdPartySourcePins } from './third-party-pins-trusted.mjs';
|
|
24
|
-
import { thirdPartySignerRow } from './third-party-source-evidence.mjs';
|
|
29
|
+
import { bundleSignerRowFor, thirdPartySignerRow } from './third-party-source-evidence.mjs';
|
|
25
30
|
import { OCI_BUNDLE_SOURCE_KIND, isThirdPartyOciRow } from './third-party-subjects.mjs';
|
|
26
31
|
|
|
27
32
|
const requireFromHere = createRequire(import.meta.url);
|
|
@@ -31,6 +36,13 @@ const PUBLIC_KEY_KIND = 'public-key';
|
|
|
31
36
|
|
|
32
37
|
const KERNEL_EXPORTS = Object.freeze(['lockedBundleSignerOf', 'assertLockedBundleSignerMatches', 'LockedBundleSignerUnknownPolicyError', 'LockedBundleSignerAmbiguousPolicyError']);
|
|
33
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Whether a selection admits an OCI bundle on a git-sourced row. `Refused` is every release, customer and dist-check
|
|
41
|
+
* selection, unchanged; `DevelopVerified` only a vendor develop edition's resolve, seal and verify, whose git bundles
|
|
42
|
+
* the develop resolve verified against the source commit (`develop-git-bundles.mjs`).
|
|
43
|
+
*/
|
|
44
|
+
export const GitSourcedBundle = Object.freeze({ Refused: 'refused', DevelopVerified: 'develop-verified' });
|
|
45
|
+
|
|
34
46
|
/** A named refusal of the bundle signer plane. */
|
|
35
47
|
export class BundleSignerError extends RefusalError {
|
|
36
48
|
constructor(message) {
|
|
@@ -56,6 +68,8 @@ export class BundleSignerMissingError extends BundleSignerError {}
|
|
|
56
68
|
export class BundleSourceOnGitRowError extends BundleSignerError {}
|
|
57
69
|
/** A resolve found an OCI host-module bundle on a git-sourced biome: such a bundle reaches an edition only through an `oci` source. */
|
|
58
70
|
export class GitSourcedHostModuleBundleError extends BundleSignerError {}
|
|
71
|
+
/** A develop resolve could not verify the OCI bundle a git-sourced biome declares (no develop row, cosign, or the content binding refused it). */
|
|
72
|
+
export class DevelopGitBundleError extends BundleSignerError {}
|
|
59
73
|
/** The loaded kernel does not export what the bundle signer plane needs. */
|
|
60
74
|
export class BundleSignerKernelUnsupportedError extends BundleSignerError {}
|
|
61
75
|
/** Several OCI rows were refused in one pass; `.errors` holds each row's own refusal. */
|
|
@@ -98,6 +112,13 @@ function assertNotGitSourced(subject) {
|
|
|
98
112
|
}
|
|
99
113
|
}
|
|
100
114
|
|
|
115
|
+
/** Refuses a git-sourced subject unless the selection admits develop git bundles and the subject is a biome row. */
|
|
116
|
+
function assertGitSourceAdmitted(subject, gitSourcedBundle) {
|
|
117
|
+
if (subject.source === undefined) {return;}
|
|
118
|
+
if (gitSourcedBundle === GitSourcedBundle.DevelopVerified && subject.componentKey === undefined) {return;}
|
|
119
|
+
assertNotGitSourced(subject);
|
|
120
|
+
}
|
|
121
|
+
|
|
101
122
|
const rowsOf = (policy, policyId) => policy.policies.filter((row) => row.policyId === policyId);
|
|
102
123
|
|
|
103
124
|
/**
|
|
@@ -105,7 +126,7 @@ const rowsOf = (policy, policyId) => policy.policies.filter((row) => row.policyI
|
|
|
105
126
|
* firstPartyPolicyId: string|undefined, schemas: object, kernel?: object}} options
|
|
106
127
|
* @returns {{policyIdFor: (subject: object) => string, signerFor: (subject: object) => object, assertSealed: (subject: object, stated: object|undefined) => void}}
|
|
107
128
|
*/
|
|
108
|
-
export function createBundleSignerSelection({ policy, thirdPartyPins, firstPartyPolicyId, schemas, kernel }) {
|
|
129
|
+
export function createBundleSignerSelection({ policy, thirdPartyPins, firstPartyPolicyId, schemas, kernel, gitSourcedBundle = GitSourcedBundle.Refused }) {
|
|
109
130
|
let loaded = kernel;
|
|
110
131
|
const kernelExports = () => (loaded ??= loadBundleSignerKernel());
|
|
111
132
|
|
|
@@ -155,6 +176,24 @@ export function createBundleSignerSelection({ policy, thirdPartyPins, firstParty
|
|
|
155
176
|
return row;
|
|
156
177
|
}
|
|
157
178
|
|
|
179
|
+
// A git-sourced biome's develop bundle: the ONE develop row of the source's repository (a host module never reaches here:
|
|
180
|
+
// the resolve refuses an OCI host module on a git-sourced biome in every channel).
|
|
181
|
+
function developGitRow(subject) {
|
|
182
|
+
const label = `${describeSubject(subject)} develop bundle signer`;
|
|
183
|
+
const repository = repositoryOwnerName(canonicalPublicHttpsRepositoryUrl(subject.source.url, `${label} source url`), `${label} source url`);
|
|
184
|
+
let row;
|
|
185
|
+
try {
|
|
186
|
+
row = bundleSignerRowFor({ policy, repository, channel: EditionChannel.Develop, schemas, label });
|
|
187
|
+
} catch (error) {
|
|
188
|
+
throw new BundleSignerPolicyAbsentError(error.message);
|
|
189
|
+
}
|
|
190
|
+
requireKind(subject, row, OIDC_CERTIFICATE_KIND);
|
|
191
|
+
return onlyRow(row.policyId);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Refuses a git-sourced subject this selection does not admit; any other subject passes. */
|
|
195
|
+
const assertAdmitted = (subject) => assertGitSourceAdmitted(subject, gitSourcedBundle);
|
|
196
|
+
|
|
158
197
|
function requirePolicy(subject) {
|
|
159
198
|
if (policy === null) {
|
|
160
199
|
throw new BundleSignerPolicyAbsentError(
|
|
@@ -164,8 +203,9 @@ export function createBundleSignerSelection({ policy, thirdPartyPins, firstParty
|
|
|
164
203
|
}
|
|
165
204
|
|
|
166
205
|
function selectedRow(subject) {
|
|
167
|
-
|
|
206
|
+
assertAdmitted(subject);
|
|
168
207
|
requirePolicy(subject);
|
|
208
|
+
if (subject.source !== undefined) {return developGitRow(subject);}
|
|
169
209
|
return isThirdPartyOciRow(subject) ? thirdPartyRow(subject) : firstPartyRow(subject);
|
|
170
210
|
}
|
|
171
211
|
|
|
@@ -178,6 +218,7 @@ export function createBundleSignerSelection({ policy, thirdPartyPins, firstParty
|
|
|
178
218
|
};
|
|
179
219
|
|
|
180
220
|
return {
|
|
221
|
+
assertAdmitted,
|
|
181
222
|
policyIdFor: (subject) => selectedRow(subject).policyId,
|
|
182
223
|
signerFor,
|
|
183
224
|
assertSealed(subject, stated) {
|
|
@@ -200,7 +241,7 @@ export function createBundleSignerSelection({ policy, thirdPartyPins, firstParty
|
|
|
200
241
|
* The data root's selection, LAZY: nothing is read until the first OCI subject asks, so a lock with no OCI row never
|
|
201
242
|
* needs a policy, a pin or a kernel that speaks v33.
|
|
202
243
|
*/
|
|
203
|
-
export function loadBundleSignerSelection({ dataRoot, schemas }) {
|
|
244
|
+
export function loadBundleSignerSelection({ dataRoot, schemas, gitSourcedBundle = GitSourcedBundle.Refused }) {
|
|
204
245
|
let selection;
|
|
205
246
|
const resolved = () => {
|
|
206
247
|
if (selection === undefined) {
|
|
@@ -211,11 +252,14 @@ export function loadBundleSignerSelection({ dataRoot, schemas }) {
|
|
|
211
252
|
thirdPartyPins: loadTrustedThirdPartySourcePins(dataRoot),
|
|
212
253
|
firstPartyPolicyId: config.firstPartyBundleSigner?.policyId,
|
|
213
254
|
schemas,
|
|
255
|
+
gitSourcedBundle,
|
|
214
256
|
});
|
|
215
257
|
}
|
|
216
258
|
return selection;
|
|
217
259
|
};
|
|
218
260
|
return Object.freeze({
|
|
261
|
+
// Refusing an unadmitted git-sourced row needs no data root, so it reads none.
|
|
262
|
+
assertAdmitted: (subject) => assertGitSourceAdmitted(subject, gitSourcedBundle),
|
|
219
263
|
policyIdFor: (subject) => resolved().policyIdFor(subject),
|
|
220
264
|
signerFor: (subject) => resolved().signerFor(subject),
|
|
221
265
|
assertSealed: (subject, stated) => resolved().assertSealed(subject, stated),
|
|
@@ -242,12 +286,12 @@ export function lockBundleSubjects(lock) {
|
|
|
242
286
|
* row is never checked and never resolves a data root: `selection` is used when given, else the data root's is loaded
|
|
243
287
|
* on the first OCI subject.
|
|
244
288
|
*/
|
|
245
|
-
export function assertLockBundleSigners({ lock, selection, schemas }) {
|
|
289
|
+
export function assertLockBundleSigners({ lock, selection, schemas, gitSourcedBundle = GitSourcedBundle.Refused }) {
|
|
246
290
|
const subjects = lockBundleSubjects(lock);
|
|
247
291
|
if (subjects.length === 0) {return;}
|
|
248
|
-
const chosen = selection ?? loadBundleSignerSelection({ dataRoot: dataRoot(), schemas });
|
|
292
|
+
const chosen = selection ?? loadBundleSignerSelection({ dataRoot: dataRoot(), schemas, gitSourcedBundle });
|
|
249
293
|
collectRefusals(subjects, ({ row, subject }) => {
|
|
250
|
-
|
|
294
|
+
chosen.assertAdmitted(subject);
|
|
251
295
|
chosen.assertSealed(subject, row.bundleSigner);
|
|
252
296
|
}, isRefusal, BundleSignerRefusedError);
|
|
253
297
|
}
|
|
@@ -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 (subjectServingBiome(subjects, biome.id, kind, id, enums) === undefined) {
|
|
153
|
+
if (subjectServingBiome(catalogue.images.schemaVersion, 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
|
}
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
|
|
63
63
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
64
64
|
import { join } from 'node:path';
|
|
65
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
65
66
|
|
|
66
67
|
import { adapterHostRow, assertAdapterBundlesMatchHost, fetchRegistryManifest } from './adapter-bundled-versions.mjs';
|
|
67
68
|
import {
|
|
@@ -75,6 +76,7 @@ import {
|
|
|
75
76
|
writeAuthorizationLock,
|
|
76
77
|
} from './authorization-base.mjs';
|
|
77
78
|
import { RefusalError, captureRefusal, isRefusal, throwCollectedRefusals } from './collected-refusals.mjs';
|
|
79
|
+
import { developGitBundleKey, developGitBundleSubjects } from './develop-git-bundles.mjs';
|
|
78
80
|
import { resolveDispatchedRuntimeComponents } from './dispatched-runtime-components.mjs';
|
|
79
81
|
import { fleetChartSetLockPath, writeEditionChartSet } from './edition-chart-set.mjs';
|
|
80
82
|
import { workspaceSection } from './edition-config.mjs';
|
|
@@ -96,7 +98,14 @@ import {
|
|
|
96
98
|
validateImmutableDistributionLock,
|
|
97
99
|
validateServiceDependencyOwnerParity,
|
|
98
100
|
} from './lib.mjs';
|
|
99
|
-
import {
|
|
101
|
+
import {
|
|
102
|
+
BundleSignerPolicyAbsentError,
|
|
103
|
+
BundleSignerRefusedError,
|
|
104
|
+
DevelopGitBundleError,
|
|
105
|
+
GitSourcedBundle,
|
|
106
|
+
GitSourcedHostModuleBundleError,
|
|
107
|
+
loadBundleSignerSelection,
|
|
108
|
+
} from './locked-bundle-signer.mjs';
|
|
100
109
|
import { admitDistributionLock } from './operation-grant-admission.mjs';
|
|
101
110
|
import { PUBLISHED_PIN_SOURCE, pinnedSource } from './pin-source.mjs';
|
|
102
111
|
import { verifiedPlatformServiceIndex } from './platform-service-ownership.mjs';
|
|
@@ -1792,7 +1801,14 @@ export function resolveUnadmittedDistributionFromInputs(
|
|
|
1792
1801
|
// trust policy selects for it. See `locked-bundle-signer.mjs`.
|
|
1793
1802
|
const bundleSignerRefusals = [];
|
|
1794
1803
|
const bundleSignerOf = (e, bundleSource, componentKey) => {
|
|
1795
|
-
const subject = {
|
|
1804
|
+
const subject = {
|
|
1805
|
+
biomeId: e.id,
|
|
1806
|
+
...(componentKey === undefined ? {} : { componentKey }),
|
|
1807
|
+
origin: e.origin,
|
|
1808
|
+
repo: e.repo,
|
|
1809
|
+
...(isGitSourced(e) ? { source: requireSourceRecord(e, sourceRecords) } : {}),
|
|
1810
|
+
bundleSource,
|
|
1811
|
+
};
|
|
1796
1812
|
if (composed?.bundleSigners === undefined) {
|
|
1797
1813
|
throw new BundleSignerPolicyAbsentError(
|
|
1798
1814
|
`${componentKey === undefined ? `biome "${e.id}"` : `host module "${componentKey}" of biome "${e.id}"`} is an OCI bundle, but this resolve was given no bundle signer selection`,
|
|
@@ -1801,12 +1817,45 @@ export function resolveUnadmittedDistributionFromInputs(
|
|
|
1801
1817
|
// Every row is selected before any is refused, so one run names them all; the lock is not built from a refused row.
|
|
1802
1818
|
return captureRefusal(bundleSignerRefusals, () => composed.bundleSigners.signerFor(subject), isRefusal);
|
|
1803
1819
|
};
|
|
1804
|
-
// A row drawn from a GIT source
|
|
1805
|
-
//
|
|
1806
|
-
//
|
|
1820
|
+
// A row drawn from a GIT source is built from the pinned source, and the manifest's biome-level `bundleSource` names an
|
|
1821
|
+
// artifact its release lane publishes, not one proven to be built from this commit. So, at the copy point:
|
|
1822
|
+
// - with `composed.developGitBundles` (a VENDOR DEVELOP resolve, XEMA-2456) the row carries the bundle the develop
|
|
1823
|
+
// resolve verified for it (`develop-git-bundles.mjs`: the develop signer at the attested commit, content-bound to
|
|
1824
|
+
// the frozen one), by digest, and its develop bundle signer. A git-sourced OCI row the resolve did not verify is
|
|
1825
|
+
// refused, never stripped;
|
|
1826
|
+
// - otherwise (release, customer, dist-check) it carries neither, as before; the release refuses the declaration.
|
|
1827
|
+
// An OCI host-module bundle on a git-sourced biome is refused below in every channel. (An entry of a declared `oci`
|
|
1828
|
+
// source has a stamp but no record: not git.)
|
|
1807
1829
|
const isGitSourced = (e) => e.source !== undefined && sourceRecords.has(e.source);
|
|
1808
|
-
const
|
|
1809
|
-
|
|
1830
|
+
const developGitBundleOf = (e) => {
|
|
1831
|
+
if (composed?.developGitBundles === undefined || !isGitSourced(e) || e.bundleSource?.kind !== 'oci') {return undefined;}
|
|
1832
|
+
const verified = composed.developGitBundles.get(developGitBundleKey(e.source, e.id));
|
|
1833
|
+
if (verified === undefined) {
|
|
1834
|
+
throw new DevelopGitBundleError(`biome "${e.id}" (git source "${e.source}") declares an OCI bundle (${e.bundleSource.ociRef}) that this develop resolve did not verify`);
|
|
1835
|
+
}
|
|
1836
|
+
return verified;
|
|
1837
|
+
};
|
|
1838
|
+
const bundleSourceOf = (e) => {
|
|
1839
|
+
if (e.bundleSource === undefined) {return {};}
|
|
1840
|
+
if (!isGitSourced(e)) {return { bundleSource: e.bundleSource };}
|
|
1841
|
+
const verified = developGitBundleOf(e);
|
|
1842
|
+
return verified === undefined ? {} : { bundleSource: verified.bundleSource };
|
|
1843
|
+
};
|
|
1844
|
+
const bundleSignerFor = (e) => {
|
|
1845
|
+
if (e.bundleSource?.kind !== 'oci') {return {};}
|
|
1846
|
+
if (!isGitSourced(e)) {return { bundleSigner: bundleSignerOf(e, e.bundleSource) };}
|
|
1847
|
+
const verified = developGitBundleOf(e);
|
|
1848
|
+
if (verified === undefined) {return {};}
|
|
1849
|
+
const bundleSigner = bundleSignerOf(e, verified.bundleSource);
|
|
1850
|
+
// A bundle carried from a pinned lock (an offline re-seal) was verified under the pinned signer; a develop row rotated
|
|
1851
|
+
// since then would put into the lock a signer the bundle was never verified under, so any difference is refused.
|
|
1852
|
+
if (verified.pinnedBundleSigner !== undefined && !isDeepStrictEqual(verified.pinnedBundleSigner, bundleSigner)) {
|
|
1853
|
+
throw new DevelopGitBundleError(
|
|
1854
|
+
`biome "${e.id}" (git source "${e.source}"): the pinned edition verified ${verified.bundleSource.ociRef} under bundle signer ${JSON.stringify(verified.pinnedBundleSigner)}, but the current trust policy selects ${JSON.stringify(bundleSigner)}; resolve the develop edition to verify the bundle under the current row`,
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
return { bundleSigner };
|
|
1858
|
+
};
|
|
1810
1859
|
const hostModuleOf = (e, hostModule) => {
|
|
1811
1860
|
if (isGitSourced(e)) {
|
|
1812
1861
|
// The lock schema requires a host module's bundleSource, so an OCI one cannot be omitted: it is refused, in every
|
|
@@ -2405,7 +2454,7 @@ export async function prepareDistributionWithIndex(id, { materialize, inputs, re
|
|
|
2405
2454
|
validateImmutableBiomeIndex(inputs?.biomeIndex ?? pinned.biomeIndex),
|
|
2406
2455
|
platformServiceIndex,
|
|
2407
2456
|
);
|
|
2408
|
-
const { entries, sourceRecords } = await walkDeclaredSources({
|
|
2457
|
+
const { entries, sourceRecords, checkouts } = await walkDeclaredSources({
|
|
2409
2458
|
sources: composed.declaredSources,
|
|
2410
2459
|
...(materialize === undefined ? {} : { materialize }),
|
|
2411
2460
|
});
|
|
@@ -2416,19 +2465,33 @@ export async function prepareDistributionWithIndex(id, { materialize, inputs, re
|
|
|
2416
2465
|
inputs !== undefined && Object.hasOwn(inputs, 'storePublisherTrust')
|
|
2417
2466
|
? inputs.storePublisherTrust
|
|
2418
2467
|
: readStorePublisherTrust();
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
}
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2468
|
+
// A VENDOR DEVELOP resolve hands `inputs.developGitBundles` (develop-git-bundles.mjs); nothing else does, so a release,
|
|
2469
|
+
// customer or dist-check resolve keeps a git-sourced row bundle-less, exactly as before.
|
|
2470
|
+
const developGitBundles = inputs?.developGitBundles;
|
|
2471
|
+
const bundleSigners =
|
|
2472
|
+
inputs?.bundleSigners ??
|
|
2473
|
+
loadBundleSignerSelection({
|
|
2474
|
+
dataRoot: dataRoot(),
|
|
2475
|
+
schemas,
|
|
2476
|
+
gitSourcedBundle: developGitBundles === undefined ? GitSourcedBundle.Refused : GitSourcedBundle.DevelopVerified,
|
|
2477
|
+
});
|
|
2478
|
+
const resolvedAt = new Date().toISOString();
|
|
2479
|
+
const resolveWith = (verified) =>
|
|
2480
|
+
resolveUnadmittedDistributionFromInputs(
|
|
2481
|
+
id,
|
|
2482
|
+
index,
|
|
2483
|
+
schemas,
|
|
2484
|
+
{ ...composed, sourceRecords, storePublisherTrust, bundleSigners, ...(verified === undefined ? {} : { developGitBundles: verified }) },
|
|
2485
|
+
resolvedAt,
|
|
2486
|
+
platformServiceIndex,
|
|
2487
|
+
);
|
|
2488
|
+
// Selection never reads a bundle, so the first pass selects exactly the biomes the second ships: only THEIR bundles are
|
|
2489
|
+
// verified (a source's unselected biome is never fetched), and the second pass refuses any git-sourced OCI row the
|
|
2490
|
+
// verifier did not answer for.
|
|
2491
|
+
const selectedOnly = resolveWith(undefined);
|
|
2492
|
+
if (developGitBundles === undefined) {return { lock: selectedOnly, index, schemas };}
|
|
2493
|
+
const subjects = developGitBundleSubjects({ lock: selectedOnly, index });
|
|
2494
|
+
const lock = subjects.length === 0 ? selectedOnly : resolveWith(await developGitBundles.verify({ subjects, checkouts, schemas }));
|
|
2432
2495
|
return { lock, index, schemas };
|
|
2433
2496
|
}
|
|
2434
2497
|
|
|
@@ -106,9 +106,10 @@ export function parseResolveEditionArgs(args) {
|
|
|
106
106
|
return { id, check };
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/** The in-repo lane: the previous images lock is the committed file at the target path, read before it is overwritten; none there is the first seal. */
|
|
109
110
|
export async function writeResolvedLockSet(id) {
|
|
110
111
|
await writeResolvedDistribution(id);
|
|
111
|
-
await writeResolvedImages(id, { trustedWriteV3: true });
|
|
112
|
+
await writeResolvedImages(id, { trustedWriteV3: true, previousFromTarget: true });
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
export async function checkResolvedLockSet(id) {
|