@kungfu-tech/buildchain 4.0.2-alpha.8 → 4.0.2
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/AGENTS.md +10 -1
- package/CONTRIBUTING.md +24 -0
- package/README.md +2 -2
- package/actions/promote-buildchain-ref/README.md +1 -1
- package/actions/v4-release-candidate-promote/README.md +28 -0
- package/architecture/agent-change-map.md +64 -7
- package/architecture/ci-lane-change-budget.json +366 -0
- package/architecture/internal-capabilities.json +53 -8
- package/architecture/maintainability-debt.json +147 -93
- package/architecture/maintainability-policy.json +32 -28
- package/architecture/release-tail-contract-inventory.json +6 -6
- package/architecture/v4-architecture-constitution.md +23 -20
- package/architecture/v4-cross-platform-adopter-qualification.json +1 -1
- package/architecture/v4-delivery-authority-parity.json +2 -2
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +1 -1
- package/architecture/v4-floating-consumer-policy.json +2 -2
- package/architecture/v4-next-development-parity.json +5 -5
- package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
- package/architecture/v4-platform-stage-checkpoints.json +1 -1
- package/architecture/v4-provider-operation-journal-contract.json +5 -2
- package/architecture/v4-publication-facade-patches.json +64 -0
- package/architecture/v4-release-activation-shadow-domain.json +5 -2
- package/architecture/v4-release-topology.json +74 -39
- package/architecture/v4-rust-wasm-production-authority.json +58 -0
- package/architecture/v4-stable-publication-fence.json +5 -2
- package/architecture/v4-stage-capsule-qualification.json +2 -2
- package/architecture/v4-tail-reseal-parity.json +8 -6
- package/architecture/v4-universal-workflow-bootstrap.json +171 -0
- package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
- package/architecture/v4-universal-workflow-train-admission.json +40 -0
- package/architecture/workflow-taxonomy.json +1451 -0
- package/bin/buildchain.mjs +7 -7
- package/contracts/buildchain-v2-residuals-v1.json +57 -48
- package/contracts/dev-delivery-authority-v2.schema.json +16 -2
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
- package/dist/site/buildchain-contract.json +93 -48
- package/dist/site/buildchain-site.json +222 -69
- package/dist/site/capability-registry.json +4 -4
- package/dist/site/controller-registry.json +50 -13
- package/dist/site/kfd-claims.json +2585 -1000
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +13 -13
- package/dist/site/node-api-registry.json +120 -115
- package/dist/site/page-registry.json +204 -51
- package/dist/site/public-surface-audit.json +3205 -1219
- package/dist/site/publication-authority-registry.json +1124 -362
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
- package/dist/site/site-manifest.json +17 -17
- package/dist/site/workflow-registry.json +5061 -1659
- package/docs/MAP.md +1 -0
- package/docs/auditable-demo.md +1 -1
- package/docs/cli.md +21 -8
- package/docs/dev-delivery-warrant.md +1 -1
- package/docs/engineering-housekeeper.md +3 -3
- package/docs/kfd-support.md +26 -2
- package/docs/next-development-transition.md +2 -2
- package/docs/node-api-reference.md +190 -190
- package/docs/publication-authority.md +2 -2
- package/docs/release-candidate.md +3 -3
- package/docs/release-flow.md +67 -19
- package/docs/release-governance.md +8 -8
- package/docs/release-passport.md +27 -2
- package/docs/reusable-build-surface.md +16 -0
- package/docs/v4-adopter-delivery.md +2 -2
- package/docs/v4-production-release.md +71 -8
- package/docs/v4-rust-wasm-production-authority.md +58 -0
- package/docs/v4-stage-capsule.md +2 -2
- package/docs/v4-tail-reseal.md +1 -1
- package/docs/workflow-catalog.md +154 -0
- package/docs/workflow-path-migration.md +109 -0
- package/package.json +10 -6
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/buildchain-contract.js +1 -1
- package/packages/core/buildchain-kfd-claims.js +2 -2
- package/packages/core/buildchain-publication-authority.js +42 -26
- package/packages/core/buildchain-v4-domain.wasm +0 -0
- package/packages/core/ci-lane-change-budget.js +14 -1
- package/packages/core/controller-evidence.js +4 -1
- package/packages/core/dev-delivery-candidate-identity.js +40 -6
- package/packages/core/dev-delivery-warrant-state.js +3 -4
- package/packages/core/dev-delivery-warrant.js +12 -2
- package/packages/core/github-governance-authority.js +4 -4
- package/packages/core/kfd-adopter-manifest.js +46 -47
- package/packages/core/next-development-projection.js +2 -2
- package/packages/core/paper-agent-entry.js +30 -4
- package/packages/core/paper-fleet.js +1 -1
- package/packages/core/paper-runtime-channels.js +348 -0
- package/packages/core/paper-scaffold-content.js +10 -0
- package/packages/core/paper.js +37 -71
- package/packages/core/release-line-dry-run.js +1 -1
- package/packages/core/release-passport-contract.js +5 -5
- package/packages/core/release-passport.js +5 -4
- package/packages/core/release-tail-provider-plane.js +68 -1048
- package/packages/core/v4-canonical-contracts.js +10 -75
- package/packages/core/v4-domain-wasm-artifact.js +7 -0
- package/packages/core/v4-domain-wasm.js +216 -0
- package/packages/core/v4-floating-consumer-evidence.js +1 -1
- package/packages/core/v4-floating-consumer-policy.js +1 -1
- package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
- package/packages/core/v4-product-publication.js +19 -349
- package/packages/core/v4-protected-publication-source.js +19 -21
- package/packages/core/v4-provider-operation-journal.js +18 -487
- package/packages/core/v4-provider-readback-idempotency.js +12 -97
- package/packages/core/v4-release-activation-shadow.js +13 -500
- package/packages/core/v4-release-invocation.js +28 -389
- package/packages/core/v4-stable-publication-fence.js +13 -342
- package/packages/core/v4-universal-workflow-bootstrap.js +586 -0
- package/scripts/binary-publication-evidence.mjs +135 -0
- package/scripts/build-contract-core.mjs +1 -14
- package/scripts/build-v4-domain-wasm.mjs +189 -0
- package/scripts/check-action-bundles.mjs +12 -2
- package/scripts/check-ci-lane-change-budget.mjs +4 -1
- package/scripts/check-core-mechanism-inventory.mjs +4 -3
- package/scripts/check-inventory.mjs +35 -44
- package/scripts/check-maintainability.mjs +16 -113
- package/scripts/check-v4-floating-consumer-policy-contract.mjs +2 -2
- package/scripts/check-v4-public-dogfood-contract.mjs +22 -9
- package/scripts/check-v4-release-topology.mjs +90 -33
- package/scripts/check-v4-runtime-semantic-closure.mjs +4 -1
- package/scripts/check-v4-universal-workflow-bootstrap.mjs +266 -0
- package/scripts/check-workflow-taxonomy.mjs +6 -0
- package/scripts/copy-v4-domain-wasm.mjs +14 -0
- package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
- package/scripts/dev-delivery-authority.mjs +8 -8
- package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
- package/scripts/dev-delivery-warrant-options.mjs +14 -9
- package/scripts/dev-delivery-warrant-store.mjs +73 -7
- package/scripts/dev-delivery-warrant-transition.mjs +109 -0
- package/scripts/dev-delivery-warrant.mjs +76 -99
- package/scripts/dev-pr-auto-merge.mjs +15 -15
- package/scripts/generate-channel-build-workflow.mjs +7 -2
- package/scripts/generate-channel-promotion-workflow.mjs +7 -5
- package/scripts/generate-site-bundle.mjs +11 -11
- package/scripts/generate-v4-universal-workflow-facades.mjs +458 -0
- package/scripts/generate-workflow-taxonomy.mjs +25 -0
- package/scripts/github-output.mjs +31 -0
- package/scripts/maintainability-metrics.mjs +16 -5
- package/scripts/maintainability-public-surface.mjs +115 -0
- package/scripts/next-development-review.mjs +307 -0
- package/scripts/paper-work-fleet-cli.mjs +2 -0
- package/scripts/release-asset-client.mjs +91 -0
- package/scripts/release-candidate-resolver.mjs +9 -9
- package/scripts/source-verification-evidence.mjs +344 -0
- package/scripts/stable-candidate-qualification.mjs +1 -1
- package/scripts/universal-facade-maintainability.mjs +82 -0
- package/scripts/v4-product-publication-intent.mjs +13 -6
- package/scripts/v4-publication-settlement.mjs +211 -0
- package/scripts/v4-universal-workflow-backflow.mjs +212 -0
- package/scripts/v4-universal-workflow-engine.mjs +618 -0
- package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
- package/scripts/verify-version-state-delta.mjs +173 -0
- package/scripts/workflow-taxonomy.mjs +507 -0
- package/templates/native-dev-delivery.yml +4 -7
- package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
- package/templates/universal-buildchain-bootstrap.yml +28 -0
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
evaluateTestBudgets,
|
|
20
20
|
evaluateWorkflowBudgets,
|
|
21
21
|
} from "./maintainability-governance.mjs";
|
|
22
|
+
import { governUniversalFacadeWorkflowMetrics } from "./universal-facade-maintainability.mjs";
|
|
23
|
+
import { evaluatePublicSurface } from "./maintainability-public-surface.mjs";
|
|
22
24
|
|
|
23
25
|
function collectHotspots(
|
|
24
26
|
root,
|
|
@@ -162,116 +164,6 @@ function selectedFunction(metrics, file, name) {
|
|
|
162
164
|
return metrics.files[file]?.functions.find((entry) => entry.name === name);
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
function readJsonAtRevision(root, revision, file) {
|
|
166
|
-
return JSON.parse(gitOutput(root, ["show", `${revision}:${file}`]));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function publicSurfaceContract(entry, kind) {
|
|
170
|
-
if (kind === "cli") return { id: entry.id, usage: entry.usage };
|
|
171
|
-
if (kind === "node")
|
|
172
|
-
return {
|
|
173
|
-
export: entry.export,
|
|
174
|
-
specifier: entry.specifier,
|
|
175
|
-
target: entry.target,
|
|
176
|
-
};
|
|
177
|
-
return {
|
|
178
|
-
id: entry.id,
|
|
179
|
-
path: entry.path,
|
|
180
|
-
reusable: entry.reusable,
|
|
181
|
-
inputs: entry.inputs || [],
|
|
182
|
-
secrets: entry.secrets || [],
|
|
183
|
-
outputs: entry.outputs || [],
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function evaluatePublicSurface({ root, revision, policy }) {
|
|
188
|
-
const issues = [];
|
|
189
|
-
const lifecycleFields = policy.publicSurfacePolicy.requiredLifecycleFields;
|
|
190
|
-
const capabilityGroups = new Set(
|
|
191
|
-
readJson(root, "dist/site/capability-registry.json").groups.map(
|
|
192
|
-
(entry) => entry.id,
|
|
193
|
-
),
|
|
194
|
-
);
|
|
195
|
-
const definitions = [
|
|
196
|
-
{
|
|
197
|
-
file: "dist/site/cli-registry.json",
|
|
198
|
-
collection: "commands",
|
|
199
|
-
kind: "cli",
|
|
200
|
-
key: "id",
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
file: "dist/site/node-api-registry.json",
|
|
204
|
-
collection: "exports",
|
|
205
|
-
kind: "node",
|
|
206
|
-
key: "export",
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
file: "dist/site/workflow-registry.json",
|
|
210
|
-
collection: "workflows",
|
|
211
|
-
kind: "workflow",
|
|
212
|
-
key: "id",
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
file: "dist/site/workflow-registry.json",
|
|
216
|
-
collection: "actions",
|
|
217
|
-
kind: "action",
|
|
218
|
-
key: "id",
|
|
219
|
-
},
|
|
220
|
-
];
|
|
221
|
-
for (const definition of definitions) {
|
|
222
|
-
const current =
|
|
223
|
-
readJson(root, definition.file)[definition.collection] || [];
|
|
224
|
-
const baseline =
|
|
225
|
-
readJsonAtRevision(root, revision, definition.file)[
|
|
226
|
-
definition.collection
|
|
227
|
-
] || [];
|
|
228
|
-
const baselineByKey = new Map(
|
|
229
|
-
baseline.map((entry) => [entry[definition.key], entry]),
|
|
230
|
-
);
|
|
231
|
-
for (const entry of current) {
|
|
232
|
-
const label = `${definition.kind}:${entry[definition.key]}`;
|
|
233
|
-
for (const field of lifecycleFields) {
|
|
234
|
-
if (
|
|
235
|
-
!Object.prototype.hasOwnProperty.call(entry, field) ||
|
|
236
|
-
typeof entry[field] !== "string"
|
|
237
|
-
) {
|
|
238
|
-
issues.push(`${label}: lifecycle field ${field} is missing`);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
if (!capabilityGroups.has(entry.capabilityGroup)) {
|
|
242
|
-
issues.push(
|
|
243
|
-
`${label}: capability group ${entry.capabilityGroup || "<empty>"} is not registered`,
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
const previous = baselineByKey.get(entry[definition.key]);
|
|
247
|
-
const currentContract = publicSurfaceContract(entry, definition.kind);
|
|
248
|
-
if (
|
|
249
|
-
previous &&
|
|
250
|
-
JSON.stringify(currentContract) !==
|
|
251
|
-
JSON.stringify(publicSurfaceContract(previous, definition.kind))
|
|
252
|
-
) {
|
|
253
|
-
const approval = policy.approvedPublicSurfaceTransitions?.[label];
|
|
254
|
-
const approved =
|
|
255
|
-
approval?.fromRevision === revision &&
|
|
256
|
-
String(approval?.rationale || "").trim() &&
|
|
257
|
-
JSON.stringify(approval?.contract) ===
|
|
258
|
-
JSON.stringify(currentContract);
|
|
259
|
-
if (!approved) {
|
|
260
|
-
issues.push(
|
|
261
|
-
`${label}: existing public contract drifted from ${revision}`,
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (!previous && !entry.nonDuplicationRationale) {
|
|
266
|
-
issues.push(
|
|
267
|
-
`${label}: new public surface requires a non-duplication rationale`,
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return issues;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
167
|
function evaluateAddedFunctionBudgets({
|
|
276
168
|
file,
|
|
277
169
|
metrics,
|
|
@@ -497,12 +389,18 @@ function checkMaintainability({ root = process.cwd() } = {}) {
|
|
|
497
389
|
root,
|
|
498
390
|
extendedCoverageRevision,
|
|
499
391
|
);
|
|
392
|
+
const { governed: governedCurrent, migration: facadeMigration } =
|
|
393
|
+
governUniversalFacadeWorkflowMetrics({
|
|
394
|
+
root,
|
|
395
|
+
current,
|
|
396
|
+
workflowMetricsAtRevision,
|
|
397
|
+
});
|
|
500
398
|
const issues = evaluateExceptionGovernance({ policy });
|
|
501
399
|
issues.push(...evaluateExceptionBudget({ policy }));
|
|
502
400
|
const hotspots = collectHotspots(root, current, 20, debt.hotspots || []);
|
|
503
401
|
issues.push(
|
|
504
402
|
...evaluateDebtAuthority({
|
|
505
|
-
current,
|
|
403
|
+
current: governedCurrent,
|
|
506
404
|
policy,
|
|
507
405
|
debt,
|
|
508
406
|
capabilityIds: new Set(
|
|
@@ -518,14 +416,19 @@ function checkMaintainability({ root = process.cwd() } = {}) {
|
|
|
518
416
|
);
|
|
519
417
|
issues.push(
|
|
520
418
|
...evaluateWorkflowBudgets({
|
|
521
|
-
current,
|
|
419
|
+
current: governedCurrent,
|
|
522
420
|
baselineFiles: baselineWorkflows,
|
|
523
421
|
policy,
|
|
524
422
|
}),
|
|
525
423
|
);
|
|
526
424
|
issues.push(...evaluateRepositoryBudgets({ current, policy }));
|
|
527
425
|
issues.push(
|
|
528
|
-
...evaluatePublicSurface({
|
|
426
|
+
...evaluatePublicSurface({
|
|
427
|
+
root,
|
|
428
|
+
revision: enforcementRevision,
|
|
429
|
+
policy,
|
|
430
|
+
migration: facadeMigration,
|
|
431
|
+
}),
|
|
529
432
|
);
|
|
530
433
|
if (issues.length > 0) {
|
|
531
434
|
throw new Error(`maintainability check failed:\n- ${issues.join("\n- ")}`);
|
|
@@ -80,7 +80,7 @@ function assertPersistedSelectors() {
|
|
|
80
80
|
const selector = match[2];
|
|
81
81
|
const protectedBootstrap =
|
|
82
82
|
relative ===
|
|
83
|
-
".github/workflows/
|
|
83
|
+
".github/workflows/self-ops-promotion-recovery.yml" &&
|
|
84
84
|
match[1] === ".github/workflows/.release-candidate-promote.yml" &&
|
|
85
85
|
selector === "alpha/v4/v4.0";
|
|
86
86
|
const isV4 =
|
|
@@ -148,7 +148,7 @@ export function checkV4FloatingConsumerPolicyContract() {
|
|
|
148
148
|
"Resolve controller identities",
|
|
149
149
|
"Install Buildchain runtime dependencies",
|
|
150
150
|
]);
|
|
151
|
-
const stageCanary = read(".github/workflows/
|
|
151
|
+
const stageCanary = read(".github/workflows/public-build-stage-capsule-canary.yml");
|
|
152
152
|
if (
|
|
153
153
|
!stageCanary.includes("consumer-admission:") ||
|
|
154
154
|
!stageCanary.includes("needs: consumer-admission")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import { readWorkflowTaxonomy, workflowPath } from "./workflow-taxonomy.mjs";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
|
|
@@ -8,8 +9,8 @@ const DEFAULT_ROOT = path.resolve(
|
|
|
8
9
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
9
10
|
"..",
|
|
10
11
|
);
|
|
11
|
-
const CALLER_PATH = ".github/workflows/
|
|
12
|
-
const REUSABLE_PATH = ".github/workflows/
|
|
12
|
+
const CALLER_PATH = ".github/workflows/self-build-public-consumer-dogfood.yml";
|
|
13
|
+
const REUSABLE_PATH = ".github/workflows/public-build-stage-capsule-canary.yml";
|
|
13
14
|
export const V4_PUBLIC_DOGFOOD_ALPHA_REF = "v4-alpha";
|
|
14
15
|
const PRIVATE_CONSUMER = ["buildchain", "self", "dogfood"].join("-");
|
|
15
16
|
const PRIVATE_SHADOW = ["kungfu", "shadow"].join("-");
|
|
@@ -26,7 +27,7 @@ permissions:
|
|
|
26
27
|
|
|
27
28
|
jobs:
|
|
28
29
|
dogfood:
|
|
29
|
-
uses: kungfu-systems/buildchain/.github/workflows/
|
|
30
|
+
uses: kungfu-systems/buildchain/.github/workflows/public-build-stage-capsule-canary.yml@${validationRef}
|
|
30
31
|
with:
|
|
31
32
|
consumer: buildchain
|
|
32
33
|
node-version: "24"
|
|
@@ -93,10 +94,19 @@ function assertReusableWorkflow(root) {
|
|
|
93
94
|
|
|
94
95
|
function assertWorkflowInventory(root) {
|
|
95
96
|
const workflowRoot = path.join(root, ".github/workflows");
|
|
97
|
+
const taxonomy = readWorkflowTaxonomy(root);
|
|
96
98
|
for (const entry of fs.readdirSync(workflowRoot, { withFileTypes: true })) {
|
|
97
99
|
if (!entry.isFile() || !/\.ya?ml$/u.test(entry.name)) continue;
|
|
98
|
-
|
|
100
|
+
let relative = `.github/workflows/${entry.name}`;
|
|
99
101
|
const text = read(root, relative);
|
|
102
|
+
const canonical = taxonomy?.entries.find(
|
|
103
|
+
(item) => workflowPath(item) === relative && item.compatibility,
|
|
104
|
+
);
|
|
105
|
+
if (canonical) {
|
|
106
|
+
if (read(root, canonical.compatibility.path) !== text)
|
|
107
|
+
fail(`${relative} differs from its public compatibility identity`);
|
|
108
|
+
relative = canonical.compatibility.path;
|
|
109
|
+
}
|
|
100
110
|
if (
|
|
101
111
|
relative !== REUSABLE_PATH &&
|
|
102
112
|
text.includes("scripts/v4-stage-capsule-qualification.mjs")
|
|
@@ -104,7 +114,7 @@ function assertWorkflowInventory(root) {
|
|
|
104
114
|
fail(`${relative} invokes the private qualification script directly`);
|
|
105
115
|
if (
|
|
106
116
|
relative !== CALLER_PATH &&
|
|
107
|
-
text.includes(".github/workflows/
|
|
117
|
+
text.includes(".github/workflows/public-build-stage-capsule-canary.yml@")
|
|
108
118
|
)
|
|
109
119
|
fail(`${relative} creates a second v4 dogfood caller`);
|
|
110
120
|
if (relative !== REUSABLE_PATH && relative !== CALLER_PATH)
|
|
@@ -113,11 +123,13 @@ function assertWorkflowInventory(root) {
|
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
function assertProtectedVerify(root) {
|
|
116
|
-
const verify = read(root, ".github/workflows/verify.yml");
|
|
126
|
+
const verify = read(root, ".github/workflows/self-build-verify.yml");
|
|
117
127
|
for (const required of [
|
|
118
128
|
"needs: stage-capsule-checkpoints",
|
|
119
|
-
"name:
|
|
120
|
-
"
|
|
129
|
+
"name: Run declared verify lifecycle (full source tests and generated artifact checks)",
|
|
130
|
+
"node .buildchain/runtime/bin/buildchain.mjs lifecycle run verify",
|
|
131
|
+
"run: node scripts/source-verification-evidence.mjs plan",
|
|
132
|
+
"run: node scripts/source-verification-evidence.mjs seal",
|
|
121
133
|
])
|
|
122
134
|
if (!verify.includes(required))
|
|
123
135
|
fail(`Verify is missing protected gate ${required}`);
|
|
@@ -150,7 +162,7 @@ function assertArchitecture(root) {
|
|
|
150
162
|
!dogfood ||
|
|
151
163
|
dogfood.callerWorkflow !== CALLER_PATH ||
|
|
152
164
|
dogfood.reusableWorkflow !==
|
|
153
|
-
"kungfu-systems/buildchain/.github/workflows/
|
|
165
|
+
"kungfu-systems/buildchain/.github/workflows/public-build-stage-capsule-canary.yml" ||
|
|
154
166
|
dogfood.runtimeBinding !== "job.workflow_sha" ||
|
|
155
167
|
dogfood.consumerSourceBinding !== "github.sha" ||
|
|
156
168
|
JSON.stringify(dogfood.executableStages) !==
|
|
@@ -193,6 +205,7 @@ function assertConsumerLifecycle(root) {
|
|
|
193
205
|
'[lifecycle.install]\ncommand = "corepack enable pnpm && corepack pnpm@11.7.0 install --frozen-lockfile"',
|
|
194
206
|
'[lifecycle.build]\ncommand = "corepack pnpm@11.7.0 run build && corepack pnpm@11.7.0 run generate:site"',
|
|
195
207
|
"[lifecycle.verify]\ncommands = [",
|
|
208
|
+
'"corepack pnpm@11.7.0 run check",',
|
|
196
209
|
])
|
|
197
210
|
if (!lifecycle.includes(declaration))
|
|
198
211
|
fail(
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import assert from "node:assert/strict";
|
|
4
4
|
import crypto from "node:crypto";
|
|
5
5
|
import fs from "node:fs";
|
|
6
|
+
import ts from "typescript";
|
|
7
|
+
import { workflowCompatibilityIdentity } from "./workflow-taxonomy.mjs";
|
|
6
8
|
import path from "node:path";
|
|
7
9
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
8
10
|
|
|
@@ -21,13 +23,35 @@ function read(relative) {
|
|
|
21
23
|
const LOCAL_MODULE_EXTENSIONS = ["", ".js", ".mjs", ".cjs"];
|
|
22
24
|
const PRIVILEGED_ENTRYPOINTS = [
|
|
23
25
|
"actions/v4-release-candidate-promote/index.js",
|
|
26
|
+
"scripts/binary-publication-evidence.mjs",
|
|
27
|
+
"scripts/next-development-review.mjs",
|
|
28
|
+
"scripts/v4-publication-settlement.mjs",
|
|
24
29
|
];
|
|
25
30
|
|
|
26
|
-
function localModuleSpecifiers(source) {
|
|
31
|
+
export function localModuleSpecifiers(source) {
|
|
27
32
|
const specifiers = [];
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
const visit = (node) => {
|
|
34
|
+
let value;
|
|
35
|
+
if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node))
|
|
36
|
+
value = node.moduleSpecifier;
|
|
37
|
+
else if (
|
|
38
|
+
ts.isCallExpression(node) &&
|
|
39
|
+
node.expression.kind === ts.SyntaxKind.ImportKeyword
|
|
40
|
+
)
|
|
41
|
+
value = node.arguments[0];
|
|
42
|
+
if (value && ts.isStringLiteral(value) && value.text.startsWith("."))
|
|
43
|
+
specifiers.push(value.text);
|
|
44
|
+
ts.forEachChild(node, visit);
|
|
45
|
+
};
|
|
46
|
+
visit(
|
|
47
|
+
ts.createSourceFile(
|
|
48
|
+
"module.mjs",
|
|
49
|
+
source,
|
|
50
|
+
ts.ScriptTarget.Latest,
|
|
51
|
+
true,
|
|
52
|
+
ts.ScriptKind.JS,
|
|
53
|
+
),
|
|
54
|
+
);
|
|
31
55
|
return [...new Set(specifiers)].sort();
|
|
32
56
|
}
|
|
33
57
|
|
|
@@ -83,6 +107,13 @@ function rootedPathSet(paths) {
|
|
|
83
107
|
.digest("hex")}`;
|
|
84
108
|
}
|
|
85
109
|
|
|
110
|
+
function fileSha256(relative) {
|
|
111
|
+
return `sha256:${crypto
|
|
112
|
+
.createHash("sha256")
|
|
113
|
+
.update(fs.readFileSync(path.join(root, relative)))
|
|
114
|
+
.digest("hex")}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
86
117
|
function productionFiles(relative, extensions) {
|
|
87
118
|
const absolute = path.join(root, relative);
|
|
88
119
|
if (!fs.existsSync(absolute)) return [];
|
|
@@ -128,6 +159,12 @@ export function discoverV4ReleaseAuthorityClosure() {
|
|
|
128
159
|
/(?:createV4ReleaseReceipt|release-receipt\.json|V4_RELEASE_RECEIPT_CONTRACT)/u,
|
|
129
160
|
);
|
|
130
161
|
const privilegedModules = discoverStaticModuleClosure(PRIVILEGED_ENTRYPOINTS);
|
|
162
|
+
const rustWasmArtifact = "packages/core/buildchain-v4-domain.wasm";
|
|
163
|
+
const rustWasmDistributions = [
|
|
164
|
+
"actions/promote-buildchain-ref/dist/buildchain-v4-domain.wasm",
|
|
165
|
+
"actions/release-tail/dist/buildchain-v4-domain.wasm",
|
|
166
|
+
"actions/v4-release-candidate-promote/dist/buildchain-v4-domain.wasm",
|
|
167
|
+
];
|
|
131
168
|
const legacyEngineModules = productionFiles(
|
|
132
169
|
"actions/promote-buildchain-ref",
|
|
133
170
|
[".js", ".mjs", ".cjs"],
|
|
@@ -153,6 +190,17 @@ export function discoverV4ReleaseAuthorityClosure() {
|
|
|
153
190
|
modules: privilegedModules,
|
|
154
191
|
root: rootedPathSet(privilegedModules),
|
|
155
192
|
},
|
|
193
|
+
rustWasmAuthority: {
|
|
194
|
+
loader: "packages/core/v4-domain-wasm.js",
|
|
195
|
+
metadata: "packages/core/v4-domain-wasm-artifact.js",
|
|
196
|
+
artifact: rustWasmArtifact,
|
|
197
|
+
artifactRoot: fileSha256(rustWasmArtifact),
|
|
198
|
+
distributedArtifacts: rustWasmDistributions,
|
|
199
|
+
byteIdenticalDistributions: rustWasmDistributions.every(
|
|
200
|
+
(relative) => fileSha256(relative) === fileSha256(rustWasmArtifact),
|
|
201
|
+
),
|
|
202
|
+
fallbackWriterCount: 0,
|
|
203
|
+
},
|
|
156
204
|
legacyEngineModules,
|
|
157
205
|
};
|
|
158
206
|
}
|
|
@@ -180,33 +228,36 @@ function permission(block, name) {
|
|
|
180
228
|
function workflowSnapshot(relative) {
|
|
181
229
|
const source = read(relative);
|
|
182
230
|
const document = parseWorkflowDocument(source);
|
|
183
|
-
const jobs = document.jobs
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
block,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
"
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
231
|
+
const jobs = document.jobs
|
|
232
|
+
.filter((job) => job.id !== "universal-bootstrap")
|
|
233
|
+
.map((job) => {
|
|
234
|
+
const block = jobBlock(source, job.id);
|
|
235
|
+
const uses = job.uses || null;
|
|
236
|
+
return {
|
|
237
|
+
id: job.id,
|
|
238
|
+
kind: uses ? "reusable-call" : "runner",
|
|
239
|
+
uses,
|
|
240
|
+
permissions: {
|
|
241
|
+
contents: permission(block, "contents"),
|
|
242
|
+
idToken: permission(block, "id-token"),
|
|
243
|
+
},
|
|
244
|
+
carriers: {
|
|
245
|
+
artifactDownload: /uses:\s+actions\/download-artifact@/u.test(block),
|
|
246
|
+
artifactUpload: /uses:\s+actions\/upload-artifact@/u.test(block),
|
|
247
|
+
jobOutput: /GITHUB_OUTPUT/u.test(block),
|
|
248
|
+
},
|
|
249
|
+
mutationSignals: [
|
|
250
|
+
/contents:\s*write/u.test(block) && "contents-write",
|
|
251
|
+
/id-token:\s*write/u.test(block) && "oidc-write",
|
|
252
|
+
/(?:promote-buildchain-ref|v4-release-candidate-promote)/u.test(
|
|
253
|
+
block,
|
|
254
|
+
) && "promotion-runtime",
|
|
255
|
+
/(?:git push|npm publish|gh release (?:create|upload))/u.test(
|
|
256
|
+
block,
|
|
257
|
+
) && "direct-publication-command",
|
|
258
|
+
].filter(Boolean),
|
|
259
|
+
};
|
|
260
|
+
});
|
|
210
261
|
return {
|
|
211
262
|
path: relative,
|
|
212
263
|
triggers: document.triggers,
|
|
@@ -214,6 +265,7 @@ function workflowSnapshot(relative) {
|
|
|
214
265
|
reusableEdges: parseYamlUses(source)
|
|
215
266
|
.map(({ value }) => value)
|
|
216
267
|
.filter((value) => /\.github\/workflows\//u.test(value))
|
|
268
|
+
.filter((value) => !/\/bootstrap\.yml(?:@v4)?$/u.test(value))
|
|
217
269
|
.sort(),
|
|
218
270
|
};
|
|
219
271
|
}
|
|
@@ -313,7 +365,12 @@ export function findUnknownV4ReleaseTopology(
|
|
|
313
365
|
) {
|
|
314
366
|
const declared = new Set(workflowPaths);
|
|
315
367
|
return allWorkflowPaths
|
|
316
|
-
.filter(
|
|
368
|
+
.filter(
|
|
369
|
+
(relative) =>
|
|
370
|
+
!declared.has(
|
|
371
|
+
workflowCompatibilityIdentity(root, relative, readWorkflow(relative)),
|
|
372
|
+
),
|
|
373
|
+
)
|
|
317
374
|
.filter((relative) => {
|
|
318
375
|
const source = readWorkflow(relative);
|
|
319
376
|
const usesReleaseAuthority = parseYamlUses(source).some(({ value }) =>
|
|
@@ -403,7 +460,7 @@ function assertAuthorityClosure(ledger) {
|
|
|
403
460
|
);
|
|
404
461
|
assert.equal(
|
|
405
462
|
closure.recoveryEntry,
|
|
406
|
-
".github/workflows/
|
|
463
|
+
".github/workflows/self-ops-promotion-recovery.yml",
|
|
407
464
|
);
|
|
408
465
|
const engineSurface = [
|
|
409
466
|
".github/workflows/.release-candidate-promote.yml",
|
|
@@ -35,7 +35,10 @@ function publicSurfaceIds(root) {
|
|
|
35
35
|
return new Set([
|
|
36
36
|
...Object.keys(packageJson.exports || {}).map((id) => `export:${id}`),
|
|
37
37
|
...(cli.commands || []).map((entry) => `cli:${entry.id}`),
|
|
38
|
-
...(workflows.workflows || []).
|
|
38
|
+
...(workflows.workflows || []).flatMap((entry) => [
|
|
39
|
+
`workflow:${entry.id}`,
|
|
40
|
+
...(entry.taxonomy ? [`workflow:${entry.taxonomy.id}`] : []),
|
|
41
|
+
]),
|
|
39
42
|
...(workflows.actions || []).map((entry) => `action:${entry.id}`),
|
|
40
43
|
]);
|
|
41
44
|
}
|