@xemahq/edition-tooling 0.0.0-stage → 0.1.1
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/LICENSE +175 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/edition.d.ts +4 -0
- package/dist/commands/edition.d.ts.map +1 -0
- package/dist/commands/edition.js +58 -0
- package/dist/commands/edition.js.map +1 -0
- package/dist/edition/verify-image-evidence.bundle.mjs +72104 -0
- package/dist/edition/verify-image-evidence.bundle.provenance.json +4119 -0
- package/dist/lib/exit-codes.d.ts +6 -0
- package/dist/lib/exit-codes.d.ts.map +1 -0
- package/dist/lib/exit-codes.js +21 -0
- package/dist/lib/exit-codes.js.map +1 -0
- package/dist/runtime/edition/run-entry.d.ts +10 -0
- package/dist/runtime/edition/run-entry.d.ts.map +1 -0
- package/dist/runtime/edition/run-entry.js +49 -0
- package/dist/runtime/edition/run-entry.js.map +1 -0
- package/dist/runtime/edition/verb-map.d.ts +70 -0
- package/dist/runtime/edition/verb-map.d.ts.map +1 -0
- package/dist/runtime/edition/verb-map.js +166 -0
- package/dist/runtime/edition/verb-map.js.map +1 -0
- package/edition/README.md +291 -0
- package/edition/adapter-bundled-versions.mjs +128 -0
- package/edition/adapter-host-versions.mjs +76 -0
- package/edition/assemble-producer-input.mjs +1423 -0
- package/edition/assemble-third-party-input.mjs +348 -0
- package/edition/authored-source-check.mjs +141 -0
- package/edition/authority-binding.mjs +23 -0
- package/edition/authorization-base.mjs +357 -0
- package/edition/biome-content.mjs +327 -0
- package/edition/build-biome-index.mjs +180 -0
- package/edition/build-ledger-completeness.mjs +67 -0
- package/edition/build-ledger.mjs +107 -0
- package/edition/build-platform-service-index.mjs +292 -0
- package/edition/build-runtime-image-source-index.mjs +1197 -0
- package/edition/built-verifier.mjs +55 -0
- package/edition/candidate-edition.mjs +735 -0
- package/edition/canonical-evidence-json.mjs +82 -0
- package/edition/canonical-repository-url.mjs +61 -0
- package/edition/catalogue-edition.mjs +49 -0
- package/edition/catalogue-evidence.mjs +228 -0
- package/edition/catalogue-fetch.mjs +124 -0
- package/edition/catalogue-lock-field.mjs +41 -0
- package/edition/catalogue-pin.mjs +71 -0
- package/edition/catalogue.mjs +237 -0
- package/edition/chart-set-source-commit.mjs +97 -0
- package/edition/check-committed-image-evidence.mjs +412 -0
- package/edition/checkout-indexed-source-repositories.mjs +283 -0
- package/edition/collected-refusals.mjs +59 -0
- package/edition/comment-blanker.mjs +75 -0
- package/edition/connector-source-authority.mjs +60 -0
- package/edition/contract-authority.mjs +122 -0
- package/edition/cosign-certificate-constraints.mjs +50 -0
- package/edition/cross-repo-build-inputs.mjs +158 -0
- package/edition/customer-definition.mjs +72 -0
- package/edition/customer-edition-verbs.mjs +610 -0
- package/edition/customer-flags.mjs +15 -0
- package/edition/definition-checkout.mjs +96 -0
- package/edition/develop-build-record.mjs +122 -0
- package/edition/develop-catalogue-free-resolve.mjs +282 -0
- package/edition/develop-catalogue-free-vendor.mjs +118 -0
- package/edition/develop-channel-evidence.mjs +23 -0
- package/edition/develop-channel-record.mjs +49 -0
- package/edition/develop-channel-satellites.mjs +65 -0
- package/edition/develop-chart-roster.mjs +96 -0
- package/edition/develop-chart-set.mjs +147 -0
- package/edition/develop-current-resolution.mjs +29 -0
- package/edition/develop-edition-invariants.mjs +142 -0
- package/edition/develop-edition-resolve.mjs +250 -0
- package/edition/develop-edition.mjs +332 -0
- package/edition/develop-engine-image.mjs +97 -0
- package/edition/develop-freeze.mjs +304 -0
- package/edition/develop-git-bundles.mjs +296 -0
- package/edition/develop-graph.mjs +34 -0
- package/edition/develop-image-coordinate.mjs +85 -0
- package/edition/develop-image-probe.mjs +122 -0
- package/edition/develop-image-record.mjs +260 -0
- package/edition/develop-resolve-report.mjs +159 -0
- package/edition/develop-select-records.mjs +90 -0
- package/edition/develop-selection-line.mjs +29 -0
- package/edition/develop-selection-pins.mjs +36 -0
- package/edition/develop-snapshot-inputs.mjs +112 -0
- package/edition/develop-store-root.mjs +20 -0
- package/edition/dispatched-runtime-components.mjs +172 -0
- package/edition/dist-check.mjs +1174 -0
- package/edition/distribution-evidence-set.mjs +1064 -0
- package/edition/distribution-paths.mjs +191 -0
- package/edition/edition-artifact.mjs +529 -0
- package/edition/edition-biome-manifests.mjs +85 -0
- package/edition/edition-ceiling.mjs +182 -0
- package/edition/edition-channel.mjs +27 -0
- package/edition/edition-chart-set.mjs +104 -0
- package/edition/edition-config.mjs +374 -0
- package/edition/edition-constants.mjs +110 -0
- package/edition/edition-contract-parse.mjs +179 -0
- package/edition/edition-contract.json +100 -0
- package/edition/edition-image-seal.mjs +115 -0
- package/edition/edition-kind.mjs +10 -0
- package/edition/edition-list.mjs +35 -0
- package/edition/edition-locks.mjs +78 -0
- package/edition/edition-pin-verbs.mjs +183 -0
- package/edition/edition-pin.mjs +17 -0
- package/edition/edition-pinned-inputs.mjs +116 -0
- package/edition/edition-protocol.mjs +285 -0
- package/edition/edition-publisher.mjs +21 -0
- package/edition/edition-seal.mjs +257 -0
- package/edition/edition-source-pins.mjs +211 -0
- package/edition/edition-unpin.mjs +16 -0
- package/edition/edition-workspace.mjs +205 -0
- package/edition/evidence-checkout.mjs +439 -0
- package/edition/evidence-grammars.mjs +18 -0
- package/edition/evidence-input-mode.mjs +136 -0
- package/edition/evidence-trust-pin.mjs +392 -0
- package/edition/evidence-trust-policy.mjs +374 -0
- package/edition/external-source-walk.mjs +486 -0
- package/edition/first-party-source-ids.mjs +62 -0
- package/edition/fleet-coordinate-finality.mjs +363 -0
- package/edition/fulcio-certificate-extensions.mjs +278 -0
- package/edition/git-json.mjs +54 -0
- package/edition/git-source-auth.mjs +131 -0
- package/edition/image-delivery-entitlement-descriptor.mjs +106 -0
- package/edition/image-evidence-replay-state.mjs +242 -0
- package/edition/image-evidence.mjs +1328 -0
- package/edition/image-lock-service-rows.mjs +26 -0
- package/edition/image-subject-identity.mjs +19 -0
- package/edition/images-from-record.mjs +216 -0
- package/edition/indexes-at-pins.mjs +13 -0
- package/edition/infra-images-lock.mjs +105 -0
- package/edition/kernel-capability-domain.mjs +30 -0
- package/edition/kernel-contract-authority.mjs +526 -0
- package/edition/kernel-contract-source-path-set.mjs +96 -0
- package/edition/kernel-package.mjs +237 -0
- package/edition/kernel-pin-source.mjs +63 -0
- package/edition/kernel-protocol-choice.mjs +239 -0
- package/edition/kernel-signer-kind.mjs +23 -0
- package/edition/lib.mjs +3322 -0
- package/edition/locked-bundle-signer.mjs +297 -0
- package/edition/map-with-concurrency.mjs +19 -0
- package/edition/no-follow-file.mjs +94 -0
- package/edition/oci-evidence-verbs.mjs +421 -0
- package/edition/oci-image-source-evidence.mjs +377 -0
- package/edition/operation-grant-admission.mjs +285 -0
- package/edition/operation-requirements.mjs +282 -0
- package/edition/oras-process.mjs +35 -0
- package/edition/oras.mjs +664 -0
- package/edition/pin-source.mjs +242 -0
- package/edition/pinned-cosign.mjs +86 -0
- package/edition/plan-image-evidence-refresh.mjs +428 -0
- package/edition/platform-lock-readability.mjs +903 -0
- package/edition/platform-service-class.mjs +85 -0
- package/edition/platform-service-ownership.mjs +91 -0
- package/edition/platform-service-source-authority.mjs +105 -0
- package/edition/positive-closure.mjs +162 -0
- package/edition/previous-image-lock.mjs +25 -0
- package/edition/produce-distribution-completeness-evidence.mjs +317 -0
- package/edition/produce-edition-catalogue-evidence.mjs +252 -0
- package/edition/produce-image-delivery-entitlement-evidence.mjs +302 -0
- package/edition/produce-image-source-evidence.mjs +788 -0
- package/edition/producer-evidence-bundle.mjs +201 -0
- package/edition/producer-evidence-index-file.mjs +4 -0
- package/edition/record-refused.mjs +11 -0
- package/edition/registry-client-factory.mjs +21 -0
- package/edition/registry-credentials.mjs +225 -0
- package/edition/release-catalogue.mjs +48 -0
- package/edition/release-channel-guard.mjs +108 -0
- package/edition/release-edition-artifact.mjs +152 -0
- package/edition/release-edition.mjs +54 -0
- package/edition/remedy-command.mjs +89 -0
- package/edition/repin-evidence-trust.mjs +109 -0
- package/edition/required-resource-provider.mjs +58 -0
- package/edition/resolve-chart-set.mjs +376 -0
- package/edition/resolve-customer-edition.mjs +374 -0
- package/edition/resolve-distribution.mjs +2642 -0
- package/edition/resolve-edition.mjs +192 -0
- package/edition/resolve-images.mjs +2344 -0
- package/edition/resolve-infra-images.mjs +88 -0
- package/edition/seal-image-digests.mjs +954 -0
- package/edition/sealed-distribution-lock.mjs +22 -0
- package/edition/sealed-evidence-accept.mjs +82 -0
- package/edition/shallow-checkout.mjs +18 -0
- package/edition/sigstore-bundle-media-type.mjs +4 -0
- package/edition/source-authority.mjs +713 -0
- package/edition/source-closure.mjs +115 -0
- package/edition/store-publisher-trust.mjs +40 -0
- package/edition/strict-json.mjs +121 -0
- package/edition/string-order.mjs +5 -0
- package/edition/third-party-admission.mjs +118 -0
- package/edition/third-party-bundle-registry.mjs +349 -0
- package/edition/third-party-certificate-extensions.mjs +58 -0
- package/edition/third-party-image-pins.mjs +41 -0
- package/edition/third-party-pins-trusted.mjs +24 -0
- package/edition/third-party-producer-evidence.mjs +76 -0
- package/edition/third-party-source-check.mjs +28 -0
- package/edition/third-party-source-context.mjs +41 -0
- package/edition/third-party-source-evidence.mjs +326 -0
- package/edition/third-party-source-flags.mjs +148 -0
- package/edition/third-party-source-pins.mjs +270 -0
- package/edition/third-party-source-uniqueness.mjs +54 -0
- package/edition/third-party-source-walk.mjs +118 -0
- package/edition/third-party-source-writer.mjs +228 -0
- package/edition/third-party-subjects.mjs +128 -0
- package/edition/trust-policy-arming-verb.mjs +60 -0
- package/edition/trust-policy-arming.mjs +144 -0
- package/edition/trust-policy-image-ownership.mjs +85 -0
- package/edition/trusted-executable.mjs +166 -0
- package/edition/verifier-binding.mjs +45 -0
- package/edition/verifier-digest-pin.mjs +17 -0
- package/edition/verifier-files.mjs +8 -0
- package/edition/verifier-kernel-schemas.mjs +22 -0
- package/edition/verifier-provenance.mjs +64 -0
- package/edition/verify-catalogue-evidence.mjs +247 -0
- package/edition/verify-image-evidence.mjs +493 -0
- package/edition/verify-image-platforms.mjs +523 -0
- package/edition/why.mjs +56 -0
- package/edition/workspace-sections.mjs +287 -0
- package/package.json +83 -4
- package/README.md +0 -3
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const DISTRIBUTION_ID_PATTERN =
|
|
5
|
+
/^[a-zA-Z0-9](?:[a-zA-Z0-9._-]{0,126}[a-zA-Z0-9])?$/;
|
|
6
|
+
|
|
7
|
+
export function assertCanonicalDistributionId(distributionId) {
|
|
8
|
+
if (
|
|
9
|
+
typeof distributionId !== 'string' ||
|
|
10
|
+
!DISTRIBUTION_ID_PATTERN.test(distributionId)
|
|
11
|
+
) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
'distribution id must be a canonical 1-128 character identifier',
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return distributionId;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function assertContained(root, candidate, label) {
|
|
20
|
+
const rel = relative(root, candidate);
|
|
21
|
+
if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
|
|
22
|
+
throw new Error(`${label} escapes the distributions root`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function resolveDistributionDirectory(
|
|
27
|
+
distributionsRoot,
|
|
28
|
+
distributionId,
|
|
29
|
+
) {
|
|
30
|
+
assertCanonicalDistributionId(distributionId);
|
|
31
|
+
const root = realpathSync(distributionsRoot);
|
|
32
|
+
const expectedDirectory = join(root, distributionId);
|
|
33
|
+
if (!existsSync(expectedDirectory)) {
|
|
34
|
+
throw new Error(`distribution "${distributionId}" does not exist`);
|
|
35
|
+
}
|
|
36
|
+
const directory = realpathSync(expectedDirectory);
|
|
37
|
+
assertContained(root, directory, `distribution "${distributionId}"`);
|
|
38
|
+
if (directory !== expectedDirectory) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`distribution "${distributionId}" directory must not be a symlink`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return { root, directory };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function resolveDistributionFile(
|
|
47
|
+
distributionsRoot,
|
|
48
|
+
distributionId,
|
|
49
|
+
fileName,
|
|
50
|
+
) {
|
|
51
|
+
const { directory } = resolveDistributionDirectory(
|
|
52
|
+
distributionsRoot,
|
|
53
|
+
distributionId,
|
|
54
|
+
);
|
|
55
|
+
const expectedPath = join(directory, fileName);
|
|
56
|
+
if (!existsSync(expectedPath)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`distribution "${distributionId}" has no ${fileName} (${expectedPath})`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const path = realpathSync(expectedPath);
|
|
62
|
+
assertContained(directory, path, `${fileName} for "${distributionId}"`);
|
|
63
|
+
if (path !== expectedPath) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`${fileName} for distribution "${distributionId}" must not be a symlink`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return path;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function readBoundDistributionFile({
|
|
72
|
+
distributionsRoot,
|
|
73
|
+
distributionId,
|
|
74
|
+
fileName,
|
|
75
|
+
parse,
|
|
76
|
+
}) {
|
|
77
|
+
const path = resolveDistributionFile(
|
|
78
|
+
distributionsRoot,
|
|
79
|
+
distributionId,
|
|
80
|
+
fileName,
|
|
81
|
+
);
|
|
82
|
+
const value = parse(JSON.parse(readFileSync(path, 'utf8')));
|
|
83
|
+
if (value.distributionId !== distributionId) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`${fileName} distributionId "${value.distributionId}" does not match requested distribution "${distributionId}"`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return { path, value };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Every edition under `distributionsRoot`, sorted — DISCOVERED, never listed.
|
|
93
|
+
*
|
|
94
|
+
* An edition is a directory carrying `xema-distribution.json`; that file is
|
|
95
|
+
* what makes the directory an edition, so nothing else can be mistaken for one
|
|
96
|
+
* and a new edition needs no registration anywhere.
|
|
97
|
+
*
|
|
98
|
+
* Throws on an empty scan. A gate that iterates editions and finds none must
|
|
99
|
+
* fail rather than report success over nothing — the repeated defect in this
|
|
100
|
+
* tree is a check that reports green while executing nothing, and a literal
|
|
101
|
+
* id list is the other half of it: a narrowed list reads as coverage.
|
|
102
|
+
*
|
|
103
|
+
* `refresh-distribution-plane.mjs` carried this three-line scan privately;
|
|
104
|
+
* it lives here so the write path and the read paths cannot disagree about
|
|
105
|
+
* what an edition is.
|
|
106
|
+
*/
|
|
107
|
+
export function discoverDistributionIds(distributionsRoot) {
|
|
108
|
+
const root = realpathSync(distributionsRoot);
|
|
109
|
+
const ids = readdirSync(root, { withFileTypes: true })
|
|
110
|
+
.filter((entry) => entry.isDirectory())
|
|
111
|
+
.map((entry) => entry.name)
|
|
112
|
+
.filter((name) => existsSync(join(root, name, 'xema-distribution.json')))
|
|
113
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
114
|
+
if (ids.length === 0) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
`found no edition under ${root} — an empty scan is not a result`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return ids;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function distributionOutputPath(
|
|
123
|
+
distributionsRoot,
|
|
124
|
+
distributionId,
|
|
125
|
+
fileName,
|
|
126
|
+
) {
|
|
127
|
+
const { directory } = resolveDistributionDirectory(
|
|
128
|
+
distributionsRoot,
|
|
129
|
+
distributionId,
|
|
130
|
+
);
|
|
131
|
+
const path = resolve(directory, fileName);
|
|
132
|
+
assertContained(directory, path, `${fileName} output`);
|
|
133
|
+
if (existsSync(path) && realpathSync(path) !== path) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`${fileName} output for distribution "${distributionId}" must not be a symlink`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return path;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The directory name holding editions that are NOT yet promoted.
|
|
143
|
+
*
|
|
144
|
+
* `discoverDistributionIds` is deliberately a single-level scan, so an edition
|
|
145
|
+
* one level down is invisible to it and to `dist:check` — which is the whole
|
|
146
|
+
* mechanism of the holding pen, not an oversight.
|
|
147
|
+
*/
|
|
148
|
+
export const PENDING_EDITIONS_DIRNAME = 'editions-pending-merge';
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Every edition under `distributionsRoot`, in BOTH tiers, as
|
|
152
|
+
* `{ id, directory, pending }` — sorted, promoted tier first.
|
|
153
|
+
*
|
|
154
|
+
* WHY BOTH TIERS. A generic test suite must be able to name its subjects
|
|
155
|
+
* without naming a customer, and a customer's edition is exactly the thing that
|
|
156
|
+
* is either pending here or has moved to a root of its own. Discovering both
|
|
157
|
+
* means one expression covers the edition wherever it currently sits, so
|
|
158
|
+
* promoting it — or removing it — changes no test.
|
|
159
|
+
*
|
|
160
|
+
* THE EMPTY CASES ARE ASYMMETRIC ON PURPOSE.
|
|
161
|
+
*
|
|
162
|
+
* * The PROMOTED tier delegates to {@link discoverDistributionIds}, which
|
|
163
|
+
* THROWS on an empty scan. An empty promoted tier means the root is wrong,
|
|
164
|
+
* and a checker that iterated zero editions and reported success is this
|
|
165
|
+
* tree's most-repeated defect.
|
|
166
|
+
* * The PENDING tier may legitimately be empty — that is what a fully
|
|
167
|
+
* promoted fleet looks like — so it is not an error. A CALLER that narrows
|
|
168
|
+
* to a subset of these and finds nothing must say so out loud rather than
|
|
169
|
+
* pass in silence; that reporting duty is the caller's, because only the
|
|
170
|
+
* caller knows what it narrowed to.
|
|
171
|
+
*/
|
|
172
|
+
export function discoverEditionDirectories(distributionsRoot) {
|
|
173
|
+
const root = realpathSync(distributionsRoot);
|
|
174
|
+
const promoted = discoverDistributionIds(root).map((id) => ({
|
|
175
|
+
id,
|
|
176
|
+
directory: join(root, id),
|
|
177
|
+
pending: false,
|
|
178
|
+
}));
|
|
179
|
+
const pendingRoot = join(root, PENDING_EDITIONS_DIRNAME);
|
|
180
|
+
const pending = !existsSync(pendingRoot)
|
|
181
|
+
? []
|
|
182
|
+
: readdirSync(pendingRoot, { withFileTypes: true })
|
|
183
|
+
.filter((entry) => entry.isDirectory())
|
|
184
|
+
.map((entry) => entry.name)
|
|
185
|
+
.filter((name) =>
|
|
186
|
+
existsSync(join(pendingRoot, name, 'xema-distribution.json')),
|
|
187
|
+
)
|
|
188
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
189
|
+
.map((id) => ({ id, directory: join(pendingRoot, id), pending: true }));
|
|
190
|
+
return [...promoted, ...pending];
|
|
191
|
+
}
|