@kungfu-tech/buildchain 4.0.1-alpha.4 → 4.0.1-alpha.6
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/actions/release-tail/README.md +8 -0
- package/architecture/decisions/0002-next-development-transition.md +101 -0
- package/architecture/internal-capabilities.json +117 -8
- package/architecture/maintainability-policy.json +38 -20
- package/architecture/release-tail-contract-inventory.json +5 -2
- package/architecture/v3-core-mechanism-inventory.json +89 -0
- package/architecture/v4-adopter-delivery-parity.json +32 -5
- package/architecture/v4-capability-state-machine-manifest.json +73 -0
- package/architecture/v4-compatibility-facts-parity.json +77 -0
- package/architecture/v4-next-development-parity.json +192 -0
- package/architecture/v4-publication-rehearsal-parity.json +84 -0
- package/architecture/v4-release-train-parity.json +1 -0
- package/architecture/v4-tail-reseal-parity.json +150 -0
- package/bin/buildchain.mjs +23 -2
- package/bin/internal/adopter-delivery-cli.mjs +70 -0
- package/bin/internal/command-registry.mjs +3 -0
- package/bin/internal/compatibility-facts-cli.mjs +101 -0
- package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
- package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
- package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
- package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
- package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
- package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
- package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
- package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
- package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
- package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
- package/contracts/next-development-request-v1.schema.json +66 -0
- package/contracts/next-development-transition-v1.schema.json +292 -0
- package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
- package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
- package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
- package/contracts/v4-tail-reseal-v1.schema.json +276 -0
- package/dist/site/agent-index.json +4 -0
- package/dist/site/artifact-schemas.json +8 -0
- package/dist/site/buildchain-contract.json +1393 -28
- package/dist/site/buildchain-site.json +462 -27
- package/dist/site/capability-registry.json +17 -14
- package/dist/site/cli-registry.json +159 -1
- package/dist/site/kfd-claims.json +429 -15
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +52 -6
- package/dist/site/node-api-registry.json +13972 -9697
- package/dist/site/page-registry.json +428 -17
- package/dist/site/public-surface-audit.json +429 -11
- package/dist/site/publication-authority-registry.json +22 -4
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +21 -0
- package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
- package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
- package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
- package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
- package/dist/site/site-manifest.json +34 -10
- package/dist/site/workflow-registry.json +121 -8
- package/docs/MAP.md +7 -2
- package/docs/cli-reference.md +193 -0
- package/docs/cli.md +8 -0
- package/docs/dev-alpha-candidate-patrol.md +8 -0
- package/docs/next-development-transition.md +118 -0
- package/docs/node-api-reference.md +448 -168
- package/docs/release-tail-provider-plane.md +30 -0
- package/docs/v4-adopter-delivery.md +133 -0
- package/docs/v4-compatibility-facts.md +91 -0
- package/docs/v4-publication-rehearsal.md +130 -0
- package/docs/v4-tail-reseal.md +73 -0
- package/docs/versioning.md +4 -3
- package/package.json +29 -6
- package/packages/core/adopter-delivery-passport.js +259 -0
- package/packages/core/adopter-delivery-vectors.js +158 -0
- package/packages/core/adopter-delivery-vectors.json +77 -0
- package/packages/core/buildchain-agent-manuals.js +3 -0
- package/packages/core/buildchain-compatibility-authority.js +336 -0
- package/packages/core/buildchain-compatibility-fact.js +394 -0
- package/packages/core/buildchain-compatibility-facts.json +217 -0
- package/packages/core/buildchain-compatibility-proof.js +566 -0
- package/packages/core/buildchain-config.js +84 -0
- package/packages/core/buildchain-contract.js +93 -141
- package/packages/core/buildchain-delivery-bootstrap.js +240 -0
- package/packages/core/buildchain-delivery-infrastructure.js +164 -0
- package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
- package/packages/core/channel-candidate.js +8 -0
- package/packages/core/channel-promotion-baseline.js +55 -0
- package/packages/core/dev-alpha-candidate-selection.js +10 -2
- package/packages/core/dev-delivery-execution-transfer.js +21 -1
- package/packages/core/dev-delivery-process-boundary.js +19 -6
- package/packages/core/dev-delivery-provider-heartbeat.js +18 -6
- package/packages/core/kungfu-temporal-fact.js +557 -0
- package/packages/core/legacy-kfd-adopter-driver.js +167 -0
- package/packages/core/next-development-candidate-reservation.js +186 -0
- package/packages/core/next-development-controller.js +728 -0
- package/packages/core/next-development-projection.js +287 -0
- package/packages/core/next-development-transition.js +738 -0
- package/packages/core/paper-agent-entry.js +11 -5
- package/packages/core/paper.js +16 -5
- package/packages/core/published-delivery-authority.js +266 -0
- package/packages/core/release-passport.js +26 -8
- package/packages/core/v4-adopter-delivery-parity.js +3 -3
- package/packages/core/v4-adopter-delivery.js +359 -0
- package/packages/core/v4-canonical-contracts.js +5 -0
- package/packages/core/v4-floating-consumer-policy.js +29 -9
- package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
- package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
- package/packages/core/v4-publication-rehearsal.js +481 -0
- package/packages/core/v4-tail-reseal-contract.js +26 -0
- package/packages/core/v4-tail-reseal-github.js +178 -0
- package/packages/core/v4-tail-reseal-receipt.js +225 -0
- package/packages/core/v4-tail-reseal.js +594 -0
- package/scripts/buildchain-cli-help.mjs +30 -0
- package/scripts/check-inventory.mjs +14 -3
- package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
- package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
- package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
- package/scripts/generate-next-development-guidance.mjs +49 -0
- package/scripts/generate-release-candidate-passport.mjs +152 -0
- package/scripts/generate-site-bundle.mjs +46 -3
- package/scripts/init-repo.mjs +22 -4
- package/scripts/next-development-self-dogfood-harness.mjs +460 -0
- package/scripts/next-development-self-dogfood.mjs +597 -0
- package/scripts/next-development-transition.mjs +47 -0
- package/scripts/release-tail.mjs +51 -3
- package/scripts/resume-from-candidate-run.mjs +545 -15
- package/scripts/site-capability-metadata.mjs +28 -0
- package/scripts/v4-consumer-policy.mjs +1 -5
- package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
- package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
- package/scripts/v4-tail-reseal.mjs +416 -0
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import {
|
|
2
|
+
v4ContentRoot,
|
|
3
|
+
validateV4Clock,
|
|
4
|
+
validateV4Root,
|
|
5
|
+
} from "./v4-canonical-contracts.js";
|
|
6
|
+
import {
|
|
7
|
+
V4_TAIL_RESEAL_PLAN_CONTRACT,
|
|
8
|
+
V4_TAIL_RESEAL_PLATFORMS as PLATFORM_IDS,
|
|
9
|
+
V4_TAIL_RESEAL_PLATFORM_RUNNERS as PLATFORM_RUNNERS,
|
|
10
|
+
V4_TAIL_RESEAL_REQUEST_CONTRACT,
|
|
11
|
+
V4_TAIL_RESEAL_REUSED_STAGE_KEYS as REUSED_STAGE_KEYS,
|
|
12
|
+
} from "./v4-tail-reseal-contract.js";
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
V4_TAIL_RESEAL_PLAN_CONTRACT,
|
|
16
|
+
V4_TAIL_RESEAL_REQUEST_CONTRACT,
|
|
17
|
+
} from "./v4-tail-reseal-contract.js";
|
|
18
|
+
|
|
19
|
+
const SHA = /^[0-9a-f]{40}$/u;
|
|
20
|
+
const TOKEN = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u;
|
|
21
|
+
const V4_RUNTIME_REF = /^(?:v4-alpha|train\/v4\/v4\.0\/[A-Za-z0-9._/-]+)$/u;
|
|
22
|
+
|
|
23
|
+
export class V4TailResealFault extends Error {
|
|
24
|
+
constructor(code, path, message) {
|
|
25
|
+
super(`${path}: ${message}`);
|
|
26
|
+
this.name = "V4TailResealFault";
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.path = path;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function fault(code, path, message) {
|
|
33
|
+
throw new V4TailResealFault(code, path, message);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function exactKeys(value, expected, path) {
|
|
37
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
38
|
+
fault("invalid-tail-reseal-shape", path, "object required");
|
|
39
|
+
const actual = Object.keys(value).sort();
|
|
40
|
+
const canonical = [...expected].sort();
|
|
41
|
+
if (
|
|
42
|
+
actual.length !== canonical.length ||
|
|
43
|
+
actual.some((key, index) => key !== canonical[index])
|
|
44
|
+
)
|
|
45
|
+
fault(
|
|
46
|
+
"invalid-tail-reseal-shape",
|
|
47
|
+
path,
|
|
48
|
+
"keys do not match the closed tail-reseal contract",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function token(value, path) {
|
|
53
|
+
if (typeof value !== "string" || !TOKEN.test(value))
|
|
54
|
+
fault("invalid-tail-reseal-token", path, "ASCII identity token required");
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function text(value, path) {
|
|
59
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
60
|
+
fault("invalid-tail-reseal-text", path, "non-empty string required");
|
|
61
|
+
return value.trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function artifactPath(value, path) {
|
|
65
|
+
const normalized = text(value, path).replaceAll("\\", "/");
|
|
66
|
+
if (
|
|
67
|
+
normalized.startsWith("/") ||
|
|
68
|
+
normalized.split("/").includes("..") ||
|
|
69
|
+
normalized.startsWith(".buildchain/tail-reseal")
|
|
70
|
+
)
|
|
71
|
+
fault(
|
|
72
|
+
"invalid-tail-reseal-artifact-path",
|
|
73
|
+
path,
|
|
74
|
+
"artifact paths must be safe relative payload paths",
|
|
75
|
+
);
|
|
76
|
+
return normalized;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function sha(value, path) {
|
|
80
|
+
if (typeof value !== "string" || !SHA.test(value))
|
|
81
|
+
fault("invalid-tail-reseal-sha", path, "exact lowercase Git SHA required");
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function root(value, path) {
|
|
86
|
+
try {
|
|
87
|
+
validateV4Root(value, path);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
fault("invalid-tail-reseal-root", path, error.message);
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function clock(value, path) {
|
|
95
|
+
try {
|
|
96
|
+
validateV4Clock(value, path);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
fault("invalid-tail-reseal-clock", path, error.message);
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function positiveInteger(value, path) {
|
|
104
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
105
|
+
fault(
|
|
106
|
+
"invalid-tail-reseal-integer",
|
|
107
|
+
path,
|
|
108
|
+
"positive safe integer required",
|
|
109
|
+
);
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function sortedUnique(values, path, validate = token) {
|
|
114
|
+
if (!Array.isArray(values) || values.length === 0)
|
|
115
|
+
fault("invalid-tail-reseal-shape", path, "non-empty array required");
|
|
116
|
+
const normalized = values.map((value, index) =>
|
|
117
|
+
validate(value, `${path}/${index}`),
|
|
118
|
+
);
|
|
119
|
+
const canonical = [...new Set(normalized)].sort((left, right) =>
|
|
120
|
+
Buffer.from(left).compare(Buffer.from(right)),
|
|
121
|
+
);
|
|
122
|
+
if (
|
|
123
|
+
normalized.length !== canonical.length ||
|
|
124
|
+
normalized.some((value, index) => value !== canonical[index])
|
|
125
|
+
)
|
|
126
|
+
fault(
|
|
127
|
+
"unordered-tail-reseal-evidence",
|
|
128
|
+
path,
|
|
129
|
+
"values must be byte-sorted and duplicate-free",
|
|
130
|
+
);
|
|
131
|
+
return normalized;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function validateSource(value) {
|
|
135
|
+
exactKeys(
|
|
136
|
+
value,
|
|
137
|
+
[
|
|
138
|
+
"runId",
|
|
139
|
+
"runAttempt",
|
|
140
|
+
"sha",
|
|
141
|
+
"treeSha",
|
|
142
|
+
"sourceRoot",
|
|
143
|
+
"workflowFile",
|
|
144
|
+
"workflowName",
|
|
145
|
+
],
|
|
146
|
+
"$/source",
|
|
147
|
+
);
|
|
148
|
+
positiveInteger(value.runId, "$/source/runId");
|
|
149
|
+
positiveInteger(value.runAttempt, "$/source/runAttempt");
|
|
150
|
+
sha(value.sha, "$/source/sha");
|
|
151
|
+
sha(value.treeSha, "$/source/treeSha");
|
|
152
|
+
root(value.sourceRoot, "$/source/sourceRoot");
|
|
153
|
+
text(value.workflowFile, "$/source/workflowFile");
|
|
154
|
+
text(value.workflowName, "$/source/workflowName");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function validateTarget(value) {
|
|
158
|
+
exactKeys(value, ["channel", "ref", "baseSha", "version"], "$/target");
|
|
159
|
+
if (value.channel !== "alpha" || value.ref !== "alpha/v4/v4.0")
|
|
160
|
+
fault(
|
|
161
|
+
"tail-reseal-target-mismatch",
|
|
162
|
+
"$/target",
|
|
163
|
+
"tail reseal is limited to alpha/v4/v4.0",
|
|
164
|
+
);
|
|
165
|
+
sha(value.baseSha, "$/target/baseSha");
|
|
166
|
+
if (!/^4\.0\.0-alpha\.\d+$/u.test(value.version))
|
|
167
|
+
fault(
|
|
168
|
+
"tail-reseal-target-mismatch",
|
|
169
|
+
"$/target/version",
|
|
170
|
+
"v4 Alpha version required",
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function validateRuntime(value) {
|
|
175
|
+
exactKeys(
|
|
176
|
+
value,
|
|
177
|
+
["repository", "ref", "sha", "contractRoot", "consumerPolicyReceiptRoot"],
|
|
178
|
+
"$/runtime",
|
|
179
|
+
);
|
|
180
|
+
if (value.repository !== "kungfu-systems/buildchain")
|
|
181
|
+
fault(
|
|
182
|
+
"tail-reseal-runtime-mismatch",
|
|
183
|
+
"$/runtime/repository",
|
|
184
|
+
"official Buildchain runtime required",
|
|
185
|
+
);
|
|
186
|
+
if (!V4_RUNTIME_REF.test(value.ref))
|
|
187
|
+
fault(
|
|
188
|
+
"tail-reseal-runtime-mismatch",
|
|
189
|
+
"$/runtime/ref",
|
|
190
|
+
"v4-alpha or a transient v4 train is required",
|
|
191
|
+
);
|
|
192
|
+
sha(value.sha, "$/runtime/sha");
|
|
193
|
+
root(value.contractRoot, "$/runtime/contractRoot");
|
|
194
|
+
root(value.consumerPolicyReceiptRoot, "$/runtime/consumerPolicyReceiptRoot");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function validateWarrant(value) {
|
|
198
|
+
exactKeys(
|
|
199
|
+
value,
|
|
200
|
+
[
|
|
201
|
+
"candidateId",
|
|
202
|
+
"generation",
|
|
203
|
+
"fencingToken",
|
|
204
|
+
"status",
|
|
205
|
+
"lineageRoot",
|
|
206
|
+
"qualificationRoot",
|
|
207
|
+
"stateReadbackRoot",
|
|
208
|
+
],
|
|
209
|
+
"$/warrant",
|
|
210
|
+
);
|
|
211
|
+
token(value.candidateId, "$/warrant/candidateId");
|
|
212
|
+
positiveInteger(value.generation, "$/warrant/generation");
|
|
213
|
+
token(value.fencingToken, "$/warrant/fencingToken");
|
|
214
|
+
if (value.status !== "qualified")
|
|
215
|
+
fault(
|
|
216
|
+
"tail-reseal-warrant-ineligible",
|
|
217
|
+
"$/warrant/status",
|
|
218
|
+
"exact qualified Warrant required",
|
|
219
|
+
);
|
|
220
|
+
root(value.lineageRoot, "$/warrant/lineageRoot");
|
|
221
|
+
root(value.qualificationRoot, "$/warrant/qualificationRoot");
|
|
222
|
+
root(value.stateReadbackRoot, "$/warrant/stateReadbackRoot");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function validateRetention(value, evaluatedAt) {
|
|
226
|
+
exactKeys(
|
|
227
|
+
value,
|
|
228
|
+
["status", "retainUntil", "policyRoot", "readbackRoot"],
|
|
229
|
+
"$/retention",
|
|
230
|
+
);
|
|
231
|
+
if (value.status !== "retained")
|
|
232
|
+
fault(
|
|
233
|
+
"tail-reseal-retention-invalid",
|
|
234
|
+
"$/retention/status",
|
|
235
|
+
"retained artifact status required",
|
|
236
|
+
);
|
|
237
|
+
clock(value.retainUntil, "$/retention/retainUntil");
|
|
238
|
+
if (Date.parse(value.retainUntil) <= Date.parse(evaluatedAt))
|
|
239
|
+
fault(
|
|
240
|
+
"tail-reseal-retention-expired",
|
|
241
|
+
"$/retention/retainUntil",
|
|
242
|
+
"retention must extend beyond evaluation",
|
|
243
|
+
);
|
|
244
|
+
root(value.policyRoot, "$/retention/policyRoot");
|
|
245
|
+
root(value.readbackRoot, "$/retention/readbackRoot");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function validateFailure(value) {
|
|
249
|
+
exactKeys(
|
|
250
|
+
value,
|
|
251
|
+
[
|
|
252
|
+
"platformId",
|
|
253
|
+
"stage",
|
|
254
|
+
"jobId",
|
|
255
|
+
"jobName",
|
|
256
|
+
"stepName",
|
|
257
|
+
"code",
|
|
258
|
+
"evidenceRoot",
|
|
259
|
+
],
|
|
260
|
+
"$/failure",
|
|
261
|
+
);
|
|
262
|
+
const exactFailure =
|
|
263
|
+
value.platformId === "macos-arm64" &&
|
|
264
|
+
value.stage === "signing-finalization" &&
|
|
265
|
+
value.jobName === "build / Finalize signed artifact macOS ARM64" &&
|
|
266
|
+
value.stepName === "Recompute manifest over final signed bytes";
|
|
267
|
+
if (!exactFailure)
|
|
268
|
+
fault(
|
|
269
|
+
"tail-reseal-failure-mismatch",
|
|
270
|
+
"$/failure",
|
|
271
|
+
"single known macOS signing-finalization failure required",
|
|
272
|
+
);
|
|
273
|
+
positiveInteger(value.jobId, "$/failure/jobId");
|
|
274
|
+
token(value.code, "$/failure/code");
|
|
275
|
+
root(value.evidenceRoot, "$/failure/evidenceRoot");
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function validateStageResume(value) {
|
|
279
|
+
exactKeys(
|
|
280
|
+
value,
|
|
281
|
+
["planRoot", "qualificationRoot", "zeroEffectReuse", "decisions"],
|
|
282
|
+
"$/stageResume",
|
|
283
|
+
);
|
|
284
|
+
root(value.planRoot, "$/stageResume/planRoot");
|
|
285
|
+
root(value.qualificationRoot, "$/stageResume/qualificationRoot");
|
|
286
|
+
if (value.zeroEffectReuse !== true)
|
|
287
|
+
fault(
|
|
288
|
+
"tail-reseal-capsule-effect",
|
|
289
|
+
"$/stageResume/zeroEffectReuse",
|
|
290
|
+
"Stage Capsule reuse must remain effect-pure",
|
|
291
|
+
);
|
|
292
|
+
if (!Array.isArray(value.decisions))
|
|
293
|
+
fault(
|
|
294
|
+
"invalid-tail-reseal-shape",
|
|
295
|
+
"$/stageResume/decisions",
|
|
296
|
+
"array required",
|
|
297
|
+
);
|
|
298
|
+
const stageKeys = [];
|
|
299
|
+
for (const [index, decision] of value.decisions.entries()) {
|
|
300
|
+
const path = `$/stageResume/decisions/${index}`;
|
|
301
|
+
exactKeys(
|
|
302
|
+
decision,
|
|
303
|
+
["stageKey", "decision", "capsuleRoot", "evidenceRoot"],
|
|
304
|
+
path,
|
|
305
|
+
);
|
|
306
|
+
stageKeys.push(token(decision.stageKey, `${path}/stageKey`));
|
|
307
|
+
if (decision.decision !== "reuse")
|
|
308
|
+
fault(
|
|
309
|
+
"tail-reseal-rebuild-required",
|
|
310
|
+
`${path}/decision`,
|
|
311
|
+
"all pre-tail stages must be exact reusable capsules",
|
|
312
|
+
);
|
|
313
|
+
root(decision.capsuleRoot, `${path}/capsuleRoot`);
|
|
314
|
+
root(decision.evidenceRoot, `${path}/evidenceRoot`);
|
|
315
|
+
}
|
|
316
|
+
if (JSON.stringify(stageKeys) !== JSON.stringify(REUSED_STAGE_KEYS))
|
|
317
|
+
fault(
|
|
318
|
+
"tail-reseal-stage-coverage-mismatch",
|
|
319
|
+
"$/stageResume/decisions",
|
|
320
|
+
"exact install, build, verify, and package reuse proof is required for every platform",
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function validateSigning(value, evaluatedAt) {
|
|
325
|
+
exactKeys(
|
|
326
|
+
value,
|
|
327
|
+
[
|
|
328
|
+
"authorityRepository",
|
|
329
|
+
"authorityRunId",
|
|
330
|
+
"runtimeSha",
|
|
331
|
+
"requestRoot",
|
|
332
|
+
"delegationRoot",
|
|
333
|
+
"resultArtifact",
|
|
334
|
+
"resultArtifactRoot",
|
|
335
|
+
"credentialAuthorityId",
|
|
336
|
+
"credentialScopeRoot",
|
|
337
|
+
"credentialLeaseRoot",
|
|
338
|
+
"credentialExpiresAt",
|
|
339
|
+
"providerReadbackRoot",
|
|
340
|
+
],
|
|
341
|
+
"$/signing",
|
|
342
|
+
);
|
|
343
|
+
text(value.authorityRepository, "$/signing/authorityRepository");
|
|
344
|
+
positiveInteger(value.authorityRunId, "$/signing/authorityRunId");
|
|
345
|
+
sha(value.runtimeSha, "$/signing/runtimeSha");
|
|
346
|
+
for (const field of [
|
|
347
|
+
"requestRoot",
|
|
348
|
+
"delegationRoot",
|
|
349
|
+
"resultArtifactRoot",
|
|
350
|
+
"credentialScopeRoot",
|
|
351
|
+
"credentialLeaseRoot",
|
|
352
|
+
"providerReadbackRoot",
|
|
353
|
+
])
|
|
354
|
+
root(value[field], `$/signing/${field}`);
|
|
355
|
+
text(value.resultArtifact, "$/signing/resultArtifact");
|
|
356
|
+
token(value.credentialAuthorityId, "$/signing/credentialAuthorityId");
|
|
357
|
+
clock(value.credentialExpiresAt, "$/signing/credentialExpiresAt");
|
|
358
|
+
if (Date.parse(value.credentialExpiresAt) <= Date.parse(evaluatedAt))
|
|
359
|
+
fault(
|
|
360
|
+
"tail-reseal-credential-expired",
|
|
361
|
+
"$/signing/credentialExpiresAt",
|
|
362
|
+
"live credential authority is required",
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function validateReleaseTail(value) {
|
|
367
|
+
exactKeys(
|
|
368
|
+
value,
|
|
369
|
+
[
|
|
370
|
+
"declarationRoot",
|
|
371
|
+
"transactionRoot",
|
|
372
|
+
"operationRoot",
|
|
373
|
+
"idempotencyKey",
|
|
374
|
+
"providerReadbackRoot",
|
|
375
|
+
],
|
|
376
|
+
"$/releaseTail",
|
|
377
|
+
);
|
|
378
|
+
for (const field of [
|
|
379
|
+
"declarationRoot",
|
|
380
|
+
"transactionRoot",
|
|
381
|
+
"operationRoot",
|
|
382
|
+
"providerReadbackRoot",
|
|
383
|
+
])
|
|
384
|
+
root(value[field], `$/releaseTail/${field}`);
|
|
385
|
+
token(value.idempotencyKey, "$/releaseTail/idempotencyKey");
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function validatePlatforms(values) {
|
|
389
|
+
if (!Array.isArray(values) || values.length !== PLATFORM_IDS.length)
|
|
390
|
+
fault(
|
|
391
|
+
"tail-reseal-platform-mismatch",
|
|
392
|
+
"$/platforms",
|
|
393
|
+
"exact four-platform candidate required",
|
|
394
|
+
);
|
|
395
|
+
const ids = [];
|
|
396
|
+
const names = new Set();
|
|
397
|
+
for (const [index, value] of values.entries()) {
|
|
398
|
+
const path = `$/platforms/${index}`;
|
|
399
|
+
exactKeys(
|
|
400
|
+
value,
|
|
401
|
+
[
|
|
402
|
+
"id",
|
|
403
|
+
"name",
|
|
404
|
+
"runner",
|
|
405
|
+
"artifactName",
|
|
406
|
+
"artifactRoot",
|
|
407
|
+
"artifactArchiveRoot",
|
|
408
|
+
"manifestArtifactName",
|
|
409
|
+
"manifestRoot",
|
|
410
|
+
"manifestArchiveRoot",
|
|
411
|
+
"artifactPaths",
|
|
412
|
+
"capsuleRoot",
|
|
413
|
+
],
|
|
414
|
+
path,
|
|
415
|
+
);
|
|
416
|
+
ids.push(token(value.id, `${path}/id`));
|
|
417
|
+
text(value.name, `${path}/name`);
|
|
418
|
+
text(value.runner, `${path}/runner`);
|
|
419
|
+
if (value.runner !== PLATFORM_RUNNERS[value.id])
|
|
420
|
+
fault(
|
|
421
|
+
"tail-reseal-runner-mismatch",
|
|
422
|
+
`${path}/runner`,
|
|
423
|
+
"platform runner differs from the declared v4 platform authority",
|
|
424
|
+
);
|
|
425
|
+
for (const field of ["artifactName", "manifestArtifactName"]) {
|
|
426
|
+
const name = text(value[field], `${path}/${field}`);
|
|
427
|
+
if (names.has(name))
|
|
428
|
+
fault(
|
|
429
|
+
"tail-reseal-artifact-ambiguous",
|
|
430
|
+
`${path}/${field}`,
|
|
431
|
+
"artifact names must be unique",
|
|
432
|
+
);
|
|
433
|
+
names.add(name);
|
|
434
|
+
}
|
|
435
|
+
root(value.artifactRoot, `${path}/artifactRoot`);
|
|
436
|
+
root(value.artifactArchiveRoot, `${path}/artifactArchiveRoot`);
|
|
437
|
+
root(value.manifestRoot, `${path}/manifestRoot`);
|
|
438
|
+
root(value.manifestArchiveRoot, `${path}/manifestArchiveRoot`);
|
|
439
|
+
const artifactPaths = sortedUnique(
|
|
440
|
+
value.artifactPaths,
|
|
441
|
+
`${path}/artifactPaths`,
|
|
442
|
+
artifactPath,
|
|
443
|
+
);
|
|
444
|
+
if (artifactPaths.length !== 2)
|
|
445
|
+
fault(
|
|
446
|
+
"tail-reseal-artifact-path-mismatch",
|
|
447
|
+
`${path}/artifactPaths`,
|
|
448
|
+
"exactly two declared payload roots are required",
|
|
449
|
+
);
|
|
450
|
+
root(value.capsuleRoot, `${path}/capsuleRoot`);
|
|
451
|
+
}
|
|
452
|
+
if (JSON.stringify(ids) !== JSON.stringify(PLATFORM_IDS))
|
|
453
|
+
fault(
|
|
454
|
+
"tail-reseal-platform-mismatch",
|
|
455
|
+
"$/platforms",
|
|
456
|
+
`platforms must be byte-ordered as ${PLATFORM_IDS.join(", ")}`,
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export function normalizeV4TailResealRequest(request) {
|
|
461
|
+
exactKeys(
|
|
462
|
+
request,
|
|
463
|
+
[
|
|
464
|
+
"schema",
|
|
465
|
+
"evaluatedAt",
|
|
466
|
+
"repository",
|
|
467
|
+
"source",
|
|
468
|
+
"target",
|
|
469
|
+
"runtime",
|
|
470
|
+
"warrant",
|
|
471
|
+
"retention",
|
|
472
|
+
"failure",
|
|
473
|
+
"stageResume",
|
|
474
|
+
"signing",
|
|
475
|
+
"releaseTail",
|
|
476
|
+
"platforms",
|
|
477
|
+
],
|
|
478
|
+
"$",
|
|
479
|
+
);
|
|
480
|
+
if (request.schema !== V4_TAIL_RESEAL_REQUEST_CONTRACT)
|
|
481
|
+
fault(
|
|
482
|
+
"unsupported-tail-reseal-version",
|
|
483
|
+
"$/schema",
|
|
484
|
+
"unsupported v4 tail-reseal request",
|
|
485
|
+
);
|
|
486
|
+
clock(request.evaluatedAt, "$/evaluatedAt");
|
|
487
|
+
text(request.repository, "$/repository");
|
|
488
|
+
validateSource(request.source);
|
|
489
|
+
validateTarget(request.target);
|
|
490
|
+
validateRuntime(request.runtime);
|
|
491
|
+
validateWarrant(request.warrant);
|
|
492
|
+
validateRetention(request.retention, request.evaluatedAt);
|
|
493
|
+
validateFailure(request.failure);
|
|
494
|
+
validateStageResume(request.stageResume);
|
|
495
|
+
validateSigning(request.signing, request.evaluatedAt);
|
|
496
|
+
validateReleaseTail(request.releaseTail);
|
|
497
|
+
validatePlatforms(request.platforms);
|
|
498
|
+
if (request.signing.runtimeSha !== request.runtime.sha)
|
|
499
|
+
fault(
|
|
500
|
+
"tail-reseal-signing-runtime-mismatch",
|
|
501
|
+
"$/signing/runtimeSha",
|
|
502
|
+
"signing authority runtime differs from candidate runtime",
|
|
503
|
+
);
|
|
504
|
+
const capsuleRoots = new Map(
|
|
505
|
+
request.platforms.map((platform) => [platform.id, platform.capsuleRoot]),
|
|
506
|
+
);
|
|
507
|
+
for (const decision of request.stageResume.decisions) {
|
|
508
|
+
const platformId = decision.stageKey.split(":", 1)[0];
|
|
509
|
+
if (decision.capsuleRoot !== capsuleRoots.get(platformId))
|
|
510
|
+
fault(
|
|
511
|
+
"tail-reseal-capsule-mismatch",
|
|
512
|
+
"$/stageResume/decisions",
|
|
513
|
+
`Stage Capsule root drifted for ${platformId}`,
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
return structuredClone(request);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export function planV4TailReseal(request) {
|
|
520
|
+
const normalized = normalizeV4TailResealRequest(request);
|
|
521
|
+
const payload = {
|
|
522
|
+
schema: V4_TAIL_RESEAL_PLAN_CONTRACT,
|
|
523
|
+
mode: "production",
|
|
524
|
+
productionAuthority: "v4",
|
|
525
|
+
evaluatedAt: normalized.evaluatedAt,
|
|
526
|
+
repository: normalized.repository,
|
|
527
|
+
sourceRoot: normalized.source.sourceRoot,
|
|
528
|
+
runtimeSha: normalized.runtime.sha,
|
|
529
|
+
warrantLineageRoot: normalized.warrant.lineageRoot,
|
|
530
|
+
stageResumePlanRoot: normalized.stageResume.planRoot,
|
|
531
|
+
retainedPlatformRoots: normalized.platforms.map((platform) => ({
|
|
532
|
+
platformId: platform.id,
|
|
533
|
+
artifactRoot: platform.artifactRoot,
|
|
534
|
+
artifactArchiveRoot: platform.artifactArchiveRoot,
|
|
535
|
+
manifestRoot: platform.manifestRoot,
|
|
536
|
+
manifestArchiveRoot: platform.manifestArchiveRoot,
|
|
537
|
+
capsuleRoot: platform.capsuleRoot,
|
|
538
|
+
})),
|
|
539
|
+
skippedStages: ["build", "install", "package", "platform-matrix", "verify"],
|
|
540
|
+
rerunStages: [
|
|
541
|
+
"macos-signing-finalization",
|
|
542
|
+
"aggregate",
|
|
543
|
+
"candidate-passport",
|
|
544
|
+
"protected-readback",
|
|
545
|
+
],
|
|
546
|
+
capsuleReuse: {
|
|
547
|
+
authority: "content-addressed-stage-capsule",
|
|
548
|
+
effectAuthority: "none",
|
|
549
|
+
zeroExternalMutations: true,
|
|
550
|
+
qualificationRoot: normalized.stageResume.qualificationRoot,
|
|
551
|
+
},
|
|
552
|
+
signingEffect: {
|
|
553
|
+
authority: "explicit-live-release-tail",
|
|
554
|
+
platformId: "macos-arm64",
|
|
555
|
+
operationRoot: normalized.releaseTail.operationRoot,
|
|
556
|
+
idempotencyKey: normalized.releaseTail.idempotencyKey,
|
|
557
|
+
fencedBy: [
|
|
558
|
+
normalized.warrant.stateReadbackRoot,
|
|
559
|
+
normalized.signing.credentialLeaseRoot,
|
|
560
|
+
normalized.releaseTail.transactionRoot,
|
|
561
|
+
].sort(),
|
|
562
|
+
providerReadbackRoots: [
|
|
563
|
+
normalized.signing.providerReadbackRoot,
|
|
564
|
+
normalized.releaseTail.providerReadbackRoot,
|
|
565
|
+
].sort(),
|
|
566
|
+
},
|
|
567
|
+
passport: {
|
|
568
|
+
contract: "kungfu-buildchain-release-candidate-passport",
|
|
569
|
+
consumerPolicyReceiptRoot: normalized.runtime.consumerPolicyReceiptRoot,
|
|
570
|
+
sourceSha: normalized.source.sha,
|
|
571
|
+
version: normalized.target.version,
|
|
572
|
+
},
|
|
573
|
+
invalidationConditions: [
|
|
574
|
+
"artifact-byte-drift",
|
|
575
|
+
"credential-authority-drift",
|
|
576
|
+
"manifest-drift",
|
|
577
|
+
"platform-drift",
|
|
578
|
+
"prior-failure-drift",
|
|
579
|
+
"retention-expired",
|
|
580
|
+
"signer-authority-drift",
|
|
581
|
+
"source-drift",
|
|
582
|
+
"warrant-lineage-drift",
|
|
583
|
+
],
|
|
584
|
+
};
|
|
585
|
+
return {
|
|
586
|
+
...payload,
|
|
587
|
+
planRoot: v4ContentRoot("tail-reseal-plan", payload),
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
export {
|
|
592
|
+
V4_TAIL_RESEAL_PLATFORMS,
|
|
593
|
+
V4_TAIL_RESEAL_REUSED_STAGE_KEYS,
|
|
594
|
+
} from "./v4-tail-reseal-contract.js";
|
|
@@ -8,6 +8,11 @@ export const BUILDCHAIN_USAGE = `Usage:
|
|
|
8
8
|
buildchain architecture qualify --authority-revision <git-revision>
|
|
9
9
|
[--candidate-revision <git-revision>]
|
|
10
10
|
[--cwd <dir>] [--json]
|
|
11
|
+
buildchain adopter-delivery run --input <json-or-path> [--output <path>]
|
|
12
|
+
buildchain adopter-delivery verify --input <json-or-path>
|
|
13
|
+
--readback <json-or-path> [--output <path>]
|
|
14
|
+
buildchain adopter-delivery bootstrap --input <json-or-path> [--output <path>]
|
|
15
|
+
buildchain adopter-delivery archive --input <json-or-path> [--output <path>]
|
|
11
16
|
buildchain portable-cache plan --manifest <file-or-json> [--output <file>]
|
|
12
17
|
[--github-output <file>] [--json]
|
|
13
18
|
buildchain portable-cache receipt --plan <file-or-json> [--matched-key <key>]
|
|
@@ -44,6 +49,23 @@ export const BUILDCHAIN_USAGE = `Usage:
|
|
|
44
49
|
buildchain release-tail init --declaration <json-or-path> [--state <path>]
|
|
45
50
|
buildchain release-tail <status|verify> [--state <path>] [--output <path>]
|
|
46
51
|
buildchain release-tail compat --hooks-json <json-or-path> [--output <path>]
|
|
52
|
+
buildchain release-tail rehearse --capsule <absolute-path>
|
|
53
|
+
--candidate-root <absolute-path>
|
|
54
|
+
--mode <simulate|replay>
|
|
55
|
+
--state <absolute-path>
|
|
56
|
+
--evidence <absolute-path>
|
|
57
|
+
buildchain tail-reseal plan --request <request.json> [--output <plan.json>]
|
|
58
|
+
buildchain tail-reseal admit --request <request.json> [--output <admission.json>]
|
|
59
|
+
buildchain tail-reseal verify-platform --request <request.json> --platform <id>
|
|
60
|
+
[--artifact-root <dir>] [--mode retained|resealed]
|
|
61
|
+
[--provider-readback-root <sha256:...>]
|
|
62
|
+
[--output <readback.json>]
|
|
63
|
+
buildchain tail-reseal seal --request <request.json> --plan <plan.json>
|
|
64
|
+
--readbacks <dir> --passport <passport.json>
|
|
65
|
+
--protected-readback-root <sha256:...>
|
|
66
|
+
[--output <receipt.json>]
|
|
67
|
+
buildchain next-development materialize --input <request.json> [--cwd <dir>]
|
|
68
|
+
[--write] [--output <path>] [--json]
|
|
47
69
|
buildchain github-governance <plan|apply|rollback|protection-policy-plan|ruleset-policy-plan> ...
|
|
48
70
|
buildchain release <inspect|recover|finalize|abort> ...
|
|
49
71
|
buildchain transaction inspect ...
|
|
@@ -154,6 +176,14 @@ export const BUILDCHAIN_USAGE = `Usage:
|
|
|
154
176
|
[--module-fact <file>]... [--artifact <path>]...
|
|
155
177
|
[--output <file>] [--json]
|
|
156
178
|
buildchain facts verify [--cwd <dir>] --fact <file> [--json]
|
|
179
|
+
buildchain facts compatibility project [--cwd <dir>] [--registry <json-or-path>]
|
|
180
|
+
[--output <file>] [--json]
|
|
181
|
+
buildchain facts compatibility verify [--cwd <dir>] [--registry <json-or-path>] [--json]
|
|
182
|
+
buildchain facts compatibility query --query <json-or-path>
|
|
183
|
+
[--registry <json-or-path>] [--cwd <dir>] [--json]
|
|
184
|
+
buildchain facts compatibility query-template --fact-root <sha256:...>
|
|
185
|
+
[--query-id <id>] [--registry <json-or-path>]
|
|
186
|
+
[--cwd <dir>] [--json]
|
|
157
187
|
buildchain kfd ...
|
|
158
188
|
buildchain kfd hub <init|inspect|test|explain> [--cwd <dir>]
|
|
159
189
|
[--declaration <path>] [--output-dir <path>]
|
|
@@ -54,6 +54,10 @@ const requiredPaths = [
|
|
|
54
54
|
"packages/core/homebrew.js",
|
|
55
55
|
"packages/core/artifact-verification-envelope.js",
|
|
56
56
|
"packages/core/anchored-version-material.js",
|
|
57
|
+
"packages/core/next-development-transition.js",
|
|
58
|
+
"packages/core/next-development-controller.js",
|
|
59
|
+
"packages/core/next-development-candidate-reservation.js",
|
|
60
|
+
"packages/core/next-development-projection.js",
|
|
57
61
|
"packages/core/build-facts.js",
|
|
58
62
|
"packages/core/publication-package.js",
|
|
59
63
|
"packages/core/publication-reproducibility.js",
|
|
@@ -76,6 +80,8 @@ const requiredPaths = [
|
|
|
76
80
|
"docs/auditable-demo.md",
|
|
77
81
|
"contracts/auditable-demo-scenario-v1.schema.json",
|
|
78
82
|
"contracts/release-candidate-recovery-v1.schema.json",
|
|
83
|
+
"contracts/next-development-request-v1.schema.json",
|
|
84
|
+
"contracts/next-development-transition-v1.schema.json",
|
|
79
85
|
"contracts/auditable-demo-media-profiles-v1.json",
|
|
80
86
|
"contracts/evidence/auditable-demo-web-delivery-v1.json",
|
|
81
87
|
"contracts/evidence/auditable-demo-responsive-web-delivery-v1.json",
|
|
@@ -87,10 +93,15 @@ const requiredPaths = [
|
|
|
87
93
|
"contracts/fixtures/auditable-demo-responsive-web-delivery-v1/public-projection.json",
|
|
88
94
|
"contracts/fixtures/auditable-demo-responsive-web-delivery-v1/scene.json",
|
|
89
95
|
"docs/release-propagation.md",
|
|
96
|
+
"docs/next-development-transition.md",
|
|
90
97
|
"docs/site-bundle-contract.md",
|
|
91
98
|
"docs/toolkit-observability.md",
|
|
92
99
|
"docs/versioning.md",
|
|
93
100
|
"scripts/release-line-dry-run.mjs",
|
|
101
|
+
"scripts/next-development-transition.mjs",
|
|
102
|
+
"scripts/next-development-self-dogfood.mjs",
|
|
103
|
+
"scripts/next-development-self-dogfood-harness.mjs",
|
|
104
|
+
"scripts/generate-next-development-guidance.mjs",
|
|
94
105
|
"scripts/reconcile-release-governance.mjs",
|
|
95
106
|
"scripts/buildchain-channel-router.mjs",
|
|
96
107
|
"scripts/generate-channel-build-workflow.mjs",
|
|
@@ -1010,16 +1021,16 @@ for (const forbiddenSnippet of [
|
|
|
1010
1021
|
for (const requiredSnippet of [
|
|
1011
1022
|
"id-token: write",
|
|
1012
1023
|
"actions: write",
|
|
1013
|
-
"uses:
|
|
1024
|
+
"uses: kungfu-systems/buildchain/.github/workflows/.release-candidate-promote.yml@alpha/v4/v4.0",
|
|
1014
1025
|
"github.event.workflow_run.event == 'push'",
|
|
1015
1026
|
"!startsWith(github.event.workflow_run.display_title, 'chore(release): prepare v')",
|
|
1016
1027
|
"!startsWith(github.event.workflow_run.display_title, 'chore(release): release v')",
|
|
1017
1028
|
"resume-candidate-run-id:",
|
|
1018
1029
|
"resume-expected-source-tree:",
|
|
1019
1030
|
"resume-buildchain-runtime-sha:",
|
|
1020
|
-
"github-
|
|
1031
|
+
"uses: kungfu-systems/buildchain/.github/workflows/release-candidate-promote.yml@v4",
|
|
1021
1032
|
"release-passport-buildchain-self-kfd: true",
|
|
1022
|
-
"
|
|
1033
|
+
"node .buildchain/router/scripts/promotion-identity-resolver.mjs",
|
|
1023
1034
|
"release-passport-impact-json: .buildchain/release-impact.json",
|
|
1024
1035
|
]) {
|
|
1025
1036
|
if (!buildchainRefPromotionWorkflow.includes(requiredSnippet)) {
|