@kungfu-tech/buildchain 4.0.2-alpha.10 → 4.0.2-alpha.12
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/architecture/agent-change-map.md +40 -0
- package/architecture/ci-lane-change-budget.json +332 -0
- package/architecture/internal-capabilities.json +39 -0
- package/architecture/maintainability-debt.json +11 -9
- package/architecture/maintainability-policy.json +7 -7
- package/architecture/v4-release-topology.json +2 -1
- package/architecture/v4-universal-workflow-bootstrap.json +181 -0
- package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
- package/architecture/v4-universal-workflow-train-admission.json +40 -0
- package/dist/site/buildchain-contract.json +86 -41
- package/dist/site/buildchain-site.json +15 -10
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/controller-registry.json +46 -10
- package/dist/site/kfd-claims.json +154 -68
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +2 -2
- package/dist/site/node-api-registry.json +7 -7
- package/dist/site/page-registry.json +9 -4
- package/dist/site/public-surface-audit.json +158 -66
- package/dist/site/publication-authority-registry.json +67 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +6 -6
- package/dist/site/workflow-registry.json +189 -67
- package/docs/node-api-reference.md +9 -9
- package/docs/reusable-build-surface.md +16 -0
- package/package.json +2 -2
- package/packages/core/buildchain-publication-authority.js +3 -0
- package/packages/core/ci-lane-change-budget.js +14 -1
- package/packages/core/release-tail-provider-plane.js +1 -1
- package/packages/core/v4-product-publication.js +1 -1
- package/packages/core/v4-universal-workflow-bootstrap.js +596 -0
- package/scripts/check-maintainability.mjs +16 -113
- package/scripts/check-v4-release-topology.mjs +5 -2
- package/scripts/check-v4-universal-workflow-bootstrap.mjs +257 -0
- package/scripts/generate-channel-build-workflow.mjs +5 -1
- package/scripts/generate-channel-promotion-workflow.mjs +3 -2
- package/scripts/generate-v4-universal-workflow-facades.mjs +415 -0
- package/scripts/maintainability-public-surface.mjs +115 -0
- package/scripts/universal-facade-maintainability.mjs +82 -0
- package/scripts/v4-universal-workflow-backflow.mjs +212 -0
- package/scripts/v4-universal-workflow-engine.mjs +586 -0
- package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
- package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
- package/templates/universal-buildchain-bootstrap.yml +28 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import {
|
|
7
|
+
V4_UNIVERSAL_WORKFLOW_REQUEST,
|
|
8
|
+
validateV4UniversalWorkflowRequest,
|
|
9
|
+
v4UniversalWorkflowAdmissionRoot,
|
|
10
|
+
} from "../packages/core/v4-universal-workflow-bootstrap.js";
|
|
11
|
+
|
|
12
|
+
const SHA = /^[0-9a-f]{40}$/u;
|
|
13
|
+
|
|
14
|
+
function fail(message) {
|
|
15
|
+
throw new Error(message);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function canonical(value) {
|
|
19
|
+
if (Array.isArray(value)) return value.map(canonical);
|
|
20
|
+
if (value && typeof value === "object")
|
|
21
|
+
return Object.fromEntries(
|
|
22
|
+
Object.keys(value)
|
|
23
|
+
.sort((left, right) => Buffer.from(left).compare(Buffer.from(right)))
|
|
24
|
+
.map((key) => [key, canonical(value[key])]),
|
|
25
|
+
);
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function contentRoot(domain, value) {
|
|
30
|
+
const hash = crypto.createHash("sha256");
|
|
31
|
+
hash.update(domain, "utf8");
|
|
32
|
+
hash.update(Buffer.from([0]));
|
|
33
|
+
hash.update(`${JSON.stringify(canonical(value))}\n`, "utf8");
|
|
34
|
+
return `sha256:${hash.digest("hex")}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function defaultPolicy() {
|
|
38
|
+
return JSON.parse(
|
|
39
|
+
fs.readFileSync(
|
|
40
|
+
new URL(
|
|
41
|
+
"../architecture/v4-universal-workflow-train-admission.json",
|
|
42
|
+
import.meta.url,
|
|
43
|
+
),
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function exactSha(value, label) {
|
|
49
|
+
const normalized = String(value || "").toLowerCase();
|
|
50
|
+
if (!SHA.test(normalized)) fail(`${label} must be an exact Git SHA`);
|
|
51
|
+
return normalized;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function createV4UniversalSelfDogfoodRequest({
|
|
55
|
+
candidateSha,
|
|
56
|
+
consumerSha,
|
|
57
|
+
pullRequest,
|
|
58
|
+
channel,
|
|
59
|
+
policy = defaultPolicy(),
|
|
60
|
+
}) {
|
|
61
|
+
const expectedSha = exactSha(candidateSha, "candidateSha");
|
|
62
|
+
const sourceSha = exactSha(consumerSha, "consumerSha");
|
|
63
|
+
if (!Number.isSafeInteger(pullRequest) || pullRequest < 1)
|
|
64
|
+
fail("pullRequest must be a positive integer");
|
|
65
|
+
if (!["alpha", "stable", "conformance"].includes(channel))
|
|
66
|
+
fail("channel must be alpha, stable, or conformance");
|
|
67
|
+
const capability =
|
|
68
|
+
channel === "conformance"
|
|
69
|
+
? {
|
|
70
|
+
id: "bootstrap-conformance",
|
|
71
|
+
payload: {
|
|
72
|
+
schema: "kungfu-buildchain-v4-universal-bootstrap-conformance/v1",
|
|
73
|
+
expectedGovernedWorkflowCount: 40,
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
: {
|
|
77
|
+
id: "release-candidate-promote",
|
|
78
|
+
payload: {
|
|
79
|
+
schema: "kungfu-buildchain-v4-universal-release-promotion/v1",
|
|
80
|
+
inputs: {
|
|
81
|
+
channel,
|
|
82
|
+
"dry-run": true,
|
|
83
|
+
"target-ref":
|
|
84
|
+
channel === "alpha" ? "alpha/v4/v4.0" : "release/v4/v4.0",
|
|
85
|
+
"target-sha": sourceSha,
|
|
86
|
+
},
|
|
87
|
+
dryRunObservation: {
|
|
88
|
+
observedSha: sourceSha,
|
|
89
|
+
comparisonStatus: "identical",
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
return validateV4UniversalWorkflowRequest({
|
|
94
|
+
schema: V4_UNIVERSAL_WORKFLOW_REQUEST,
|
|
95
|
+
mode: "train",
|
|
96
|
+
candidate: {
|
|
97
|
+
repository: "kungfu-systems/buildchain",
|
|
98
|
+
discoveryRef: "train/v4/v4.0/universal-reusable-workflow-bootstrap",
|
|
99
|
+
expectedSha,
|
|
100
|
+
admissionRoot: v4UniversalWorkflowAdmissionRoot(policy),
|
|
101
|
+
reviewPullRequest: pullRequest,
|
|
102
|
+
},
|
|
103
|
+
consumer: {
|
|
104
|
+
repository: "kungfu-systems/buildchain",
|
|
105
|
+
workflow: ".github/workflows/universal-bootstrap-dogfood.yml",
|
|
106
|
+
sourceSha,
|
|
107
|
+
},
|
|
108
|
+
capability: {
|
|
109
|
+
id: capability.id,
|
|
110
|
+
contractRoots: policy.contractRoots,
|
|
111
|
+
permissions: { contents: "read" },
|
|
112
|
+
},
|
|
113
|
+
payload: capability.payload,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function exactResult(value, label, expectedSha, expectedChannel) {
|
|
118
|
+
if (
|
|
119
|
+
value?.schema !== "kungfu-buildchain-v4-universal-workflow-result/v1" ||
|
|
120
|
+
value.status !== "succeeded" ||
|
|
121
|
+
value.runtime?.repository !== "kungfu-systems/buildchain" ||
|
|
122
|
+
value.runtime?.sha !== expectedSha
|
|
123
|
+
)
|
|
124
|
+
fail(`${label} is not a successful exact-Train result`);
|
|
125
|
+
if (expectedChannel === "conformance") {
|
|
126
|
+
if (
|
|
127
|
+
value.output?.schema !==
|
|
128
|
+
"kungfu-buildchain-v4-universal-bootstrap-conformance-result/v1" ||
|
|
129
|
+
value.output?.status !== "candidate-engine-executed"
|
|
130
|
+
)
|
|
131
|
+
fail(`${label} did not execute the candidate conformance engine`);
|
|
132
|
+
} else if (
|
|
133
|
+
value.output?.dryRun !== true ||
|
|
134
|
+
value.output?.route?.decision !== "Fresh" ||
|
|
135
|
+
value.output?.route?.channel !== expectedChannel
|
|
136
|
+
) {
|
|
137
|
+
fail(
|
|
138
|
+
`${label} did not execute the ${expectedChannel}-shaped release route`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function verifyV4UniversalSelfDogfoodPair({
|
|
145
|
+
primary,
|
|
146
|
+
recovery,
|
|
147
|
+
expectedSha,
|
|
148
|
+
channel,
|
|
149
|
+
}) {
|
|
150
|
+
const sha = exactSha(expectedSha, "expectedSha");
|
|
151
|
+
const left = exactResult(primary, "primary result", sha, channel);
|
|
152
|
+
const right = exactResult(recovery, "recovery result", sha, channel);
|
|
153
|
+
for (const field of ["requestRoot", "capabilityRoot", "resultRoot"]) {
|
|
154
|
+
if (left[field] !== right[field])
|
|
155
|
+
fail(`primary and recovery ${field} differ`);
|
|
156
|
+
}
|
|
157
|
+
const body = {
|
|
158
|
+
schema: "kungfu-buildchain-v4-universal-self-dogfood-pair/v1",
|
|
159
|
+
channel,
|
|
160
|
+
runtimeSha: sha,
|
|
161
|
+
requestRoot: left.requestRoot,
|
|
162
|
+
capabilityRoot: left.capabilityRoot,
|
|
163
|
+
resultRoot: left.resultRoot,
|
|
164
|
+
equivalent: true,
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
...body,
|
|
168
|
+
pairRoot: contentRoot("universal-self-dogfood-pair", body),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function option(name) {
|
|
173
|
+
const index = process.argv.indexOf(`--${name}`);
|
|
174
|
+
return index >= 0 ? process.argv[index + 1] : "";
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function main() {
|
|
178
|
+
const command = process.argv[2];
|
|
179
|
+
if (command === "request") {
|
|
180
|
+
const request = createV4UniversalSelfDogfoodRequest({
|
|
181
|
+
candidateSha: option("candidate-sha"),
|
|
182
|
+
consumerSha: option("consumer-sha"),
|
|
183
|
+
pullRequest: Number(option("pull-request")),
|
|
184
|
+
channel: option("channel"),
|
|
185
|
+
});
|
|
186
|
+
process.stdout.write(`${JSON.stringify(request)}\n`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (command === "verify-pair") {
|
|
190
|
+
const result = verifyV4UniversalSelfDogfoodPair({
|
|
191
|
+
primary: JSON.parse(process.env.BUILDCHAIN_PRIMARY_RESULT_JSON || ""),
|
|
192
|
+
recovery: JSON.parse(process.env.BUILDCHAIN_RECOVERY_RESULT_JSON || ""),
|
|
193
|
+
expectedSha: option("candidate-sha"),
|
|
194
|
+
channel: option("channel"),
|
|
195
|
+
});
|
|
196
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
fail("command must be request or verify-pair");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const isMain =
|
|
203
|
+
process.argv[1] &&
|
|
204
|
+
fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
|
|
205
|
+
if (isMain) await main();
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
name: Universal Buildchain Bootstrap Recovery
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
request-json:
|
|
7
|
+
description: "Versioned exact-candidate request envelope"
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
outputs:
|
|
11
|
+
runtime-sha:
|
|
12
|
+
value: ${{ jobs.recovery-admit.outputs.runtime-sha }}
|
|
13
|
+
result-json:
|
|
14
|
+
value: ${{ jobs.recovery-execute.outputs.result-json }}
|
|
15
|
+
terminal-receipt-json:
|
|
16
|
+
value: ${{ jobs.recovery-settle.outputs.terminal-receipt-json }}
|
|
17
|
+
terminal-receipt-root:
|
|
18
|
+
value: ${{ jobs.recovery-settle.outputs.terminal-receipt-root }}
|
|
19
|
+
backflow-root:
|
|
20
|
+
value: ${{ jobs.recovery-settle.outputs.backflow-root }}
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
recovery-admit:
|
|
27
|
+
runs-on: ubuntu-24.04
|
|
28
|
+
permissions:
|
|
29
|
+
checks: read
|
|
30
|
+
contents: read
|
|
31
|
+
pull-requests: read
|
|
32
|
+
outputs:
|
|
33
|
+
runtime-sha: ${{ steps.admit.outputs.runtime-sha }}
|
|
34
|
+
admission-json: ${{ steps.admit.outputs.admission-json }}
|
|
35
|
+
steps:
|
|
36
|
+
- name: Parse exact recovery coordinates without Buildchain code
|
|
37
|
+
id: request
|
|
38
|
+
shell: bash
|
|
39
|
+
env:
|
|
40
|
+
REQUEST_JSON: ${{ inputs.request-json }}
|
|
41
|
+
run: |
|
|
42
|
+
set -euo pipefail
|
|
43
|
+
printf '%s\n' "${REQUEST_JSON}" > .buildchain-request.json
|
|
44
|
+
jq -e '
|
|
45
|
+
.schema == "kungfu-buildchain-v4-universal-workflow-request/v1" and
|
|
46
|
+
.mode == "train" and
|
|
47
|
+
.candidate.repository == "kungfu-systems/buildchain" and
|
|
48
|
+
(.candidate.discoveryRef | test("^train/v4/v4\\.[0-9]+/[A-Za-z0-9][A-Za-z0-9._/-]*$")) and
|
|
49
|
+
(.candidate.expectedSha | test("^[0-9a-f]{40}$")) and
|
|
50
|
+
(.candidate.reviewPullRequest | type == "number" and . > 0)
|
|
51
|
+
' .buildchain-request.json > /dev/null
|
|
52
|
+
{
|
|
53
|
+
echo "repository=$(jq -r '.candidate.repository' .buildchain-request.json)"
|
|
54
|
+
echo "ref=$(jq -r '.candidate.discoveryRef' .buildchain-request.json)"
|
|
55
|
+
echo "sha=$(jq -r '.candidate.expectedSha' .buildchain-request.json)"
|
|
56
|
+
echo "pr=$(jq -r '.candidate.reviewPullRequest' .buildchain-request.json)"
|
|
57
|
+
} >> "${GITHUB_OUTPUT}"
|
|
58
|
+
|
|
59
|
+
- name: Checkout exact Train candidate without persisted credentials
|
|
60
|
+
uses: actions/checkout@v7.0.0
|
|
61
|
+
with:
|
|
62
|
+
repository: ${{ steps.request.outputs.repository }}
|
|
63
|
+
ref: ${{ steps.request.outputs.ref }}
|
|
64
|
+
path: .buildchain/candidate
|
|
65
|
+
persist-credentials: false
|
|
66
|
+
|
|
67
|
+
- name: Prove exact independent review before candidate code runs
|
|
68
|
+
shell: bash
|
|
69
|
+
env:
|
|
70
|
+
GH_TOKEN: ${{ github.token }}
|
|
71
|
+
EXPECTED_SHA: ${{ steps.request.outputs.sha }}
|
|
72
|
+
REVIEW_PR: ${{ steps.request.outputs.pr }}
|
|
73
|
+
run: |
|
|
74
|
+
set -euo pipefail
|
|
75
|
+
test "$(git -C .buildchain/candidate rev-parse HEAD)" = "${EXPECTED_SHA}"
|
|
76
|
+
gh api "repos/kungfu-systems/buildchain/pulls/${REVIEW_PR}" > .buildchain-pr.json
|
|
77
|
+
gh api --paginate "repos/kungfu-systems/buildchain/pulls/${REVIEW_PR}/reviews" \
|
|
78
|
+
| jq -s 'add' > .buildchain-reviews.json
|
|
79
|
+
gh api --paginate -H 'Accept: application/vnd.github+json' \
|
|
80
|
+
"repos/kungfu-systems/buildchain/commits/${EXPECTED_SHA}/check-runs?per_page=100" \
|
|
81
|
+
| jq -s '[.[].check_runs[]]' > .buildchain-checks.json
|
|
82
|
+
jq -e --arg sha "${EXPECTED_SHA}" '
|
|
83
|
+
.head.repo.full_name == "kungfu-systems/buildchain" and
|
|
84
|
+
.head.sha == $sha and
|
|
85
|
+
.base.ref == "dev/v4/v4.0"
|
|
86
|
+
' .buildchain-pr.json > /dev/null
|
|
87
|
+
jq -e --arg sha "${EXPECTED_SHA}" '
|
|
88
|
+
any(.[]; .state == "APPROVED" and .commit_id == $sha and (.user.login | ascii_downcase) == "kungfu-origin")
|
|
89
|
+
' .buildchain-reviews.json > /dev/null
|
|
90
|
+
jq -e '
|
|
91
|
+
any(.[]; .name == "check" and .status == "completed" and .conclusion == "success")
|
|
92
|
+
' .buildchain-checks.json > /dev/null
|
|
93
|
+
|
|
94
|
+
- name: Admit candidate policy and exact-head checks
|
|
95
|
+
id: admit
|
|
96
|
+
shell: bash
|
|
97
|
+
env:
|
|
98
|
+
BUILDCHAIN_UNIVERSAL_REQUEST_JSON: ${{ inputs.request-json }}
|
|
99
|
+
BUILDCHAIN_UNIVERSAL_CONSUMER_REPOSITORY: ${{ github.repository }}
|
|
100
|
+
BUILDCHAIN_UNIVERSAL_CONSUMER_SHA: ${{ github.sha }}
|
|
101
|
+
BUILDCHAIN_UNIVERSAL_CONSUMER_WORKFLOW_REF: ${{ github.workflow_ref }}
|
|
102
|
+
EXPECTED_SHA: ${{ steps.request.outputs.sha }}
|
|
103
|
+
REVIEW_PR: ${{ steps.request.outputs.pr }}
|
|
104
|
+
run: |
|
|
105
|
+
set -euo pipefail
|
|
106
|
+
observed_at="$(date -u '+%Y-%m-%dT%H:%M:%S.000Z')"
|
|
107
|
+
jq -n --arg expected "${EXPECTED_SHA}" \
|
|
108
|
+
--arg observed_at "${observed_at}" \
|
|
109
|
+
--argjson pull_request "${REVIEW_PR}" \
|
|
110
|
+
--slurpfile reviews .buildchain-reviews.json \
|
|
111
|
+
--slurpfile checks .buildchain-checks.json '
|
|
112
|
+
{
|
|
113
|
+
repository: "kungfu-systems/buildchain",
|
|
114
|
+
pullRequest: $pull_request,
|
|
115
|
+
headSha: $expected,
|
|
116
|
+
baseRef: "dev/v4/v4.0",
|
|
117
|
+
approvals: ($reviews[0]
|
|
118
|
+
| map(select(.state == "APPROVED" and .commit_id == $expected))
|
|
119
|
+
| map({
|
|
120
|
+
reviewer: (.user.login | ascii_downcase),
|
|
121
|
+
commitSha: .commit_id,
|
|
122
|
+
submittedAt: (.submitted_at | fromdateiso8601 | strftime("%Y-%m-%dT%H:%M:%S.000Z"))
|
|
123
|
+
})),
|
|
124
|
+
checks: ($checks[0] | map(select(.status == "completed" and (.conclusion // "") != "")) | map({name, status, conclusion})),
|
|
125
|
+
observedAt: $observed_at
|
|
126
|
+
}
|
|
127
|
+
' > .buildchain-review-evidence.json
|
|
128
|
+
BUILDCHAIN_UNIVERSAL_ADMISSION_POLICY_JSON="$(jq -c '.' .buildchain/candidate/architecture/v4-universal-workflow-train-admission.json)"
|
|
129
|
+
BUILDCHAIN_UNIVERSAL_REVIEW_EVIDENCE_JSON="$(jq -c '.' .buildchain-review-evidence.json)"
|
|
130
|
+
BUILDCHAIN_UNIVERSAL_OBSERVED_SHA="${EXPECTED_SHA}"
|
|
131
|
+
BUILDCHAIN_UNIVERSAL_OBSERVED_AT="${observed_at}"
|
|
132
|
+
export BUILDCHAIN_UNIVERSAL_ADMISSION_POLICY_JSON BUILDCHAIN_UNIVERSAL_REVIEW_EVIDENCE_JSON
|
|
133
|
+
export BUILDCHAIN_UNIVERSAL_OBSERVED_SHA BUILDCHAIN_UNIVERSAL_OBSERVED_AT
|
|
134
|
+
node .buildchain/candidate/scripts/v4-universal-workflow-engine.mjs admit > .buildchain-admission.json
|
|
135
|
+
{
|
|
136
|
+
echo "runtime-sha=${EXPECTED_SHA}"
|
|
137
|
+
echo "admission-json=$(jq -c '.' .buildchain-admission.json)"
|
|
138
|
+
} >> "${GITHUB_OUTPUT}"
|
|
139
|
+
|
|
140
|
+
recovery-execute:
|
|
141
|
+
needs: recovery-admit
|
|
142
|
+
runs-on: ubuntu-24.04
|
|
143
|
+
permissions:
|
|
144
|
+
actions: write
|
|
145
|
+
artifact-metadata: write
|
|
146
|
+
attestations: write
|
|
147
|
+
checks: write
|
|
148
|
+
contents: write
|
|
149
|
+
deployments: write
|
|
150
|
+
id-token: write
|
|
151
|
+
issues: write
|
|
152
|
+
packages: write
|
|
153
|
+
pages: write
|
|
154
|
+
pull-requests: write
|
|
155
|
+
security-events: write
|
|
156
|
+
statuses: write
|
|
157
|
+
outputs:
|
|
158
|
+
result-json: ${{ steps.execute.outputs.result-json }}
|
|
159
|
+
steps:
|
|
160
|
+
- name: Checkout unchanged consumer source
|
|
161
|
+
uses: actions/checkout@v7.0.0
|
|
162
|
+
with:
|
|
163
|
+
persist-credentials: false
|
|
164
|
+
|
|
165
|
+
- name: Checkout exact admitted candidate
|
|
166
|
+
uses: actions/checkout@v7.0.0
|
|
167
|
+
with:
|
|
168
|
+
repository: kungfu-systems/buildchain
|
|
169
|
+
ref: ${{ needs.recovery-admit.outputs.runtime-sha }}
|
|
170
|
+
path: .buildchain/candidate
|
|
171
|
+
persist-credentials: false
|
|
172
|
+
|
|
173
|
+
- name: Execute only the exact admitted engine
|
|
174
|
+
id: execute
|
|
175
|
+
shell: bash
|
|
176
|
+
env:
|
|
177
|
+
BUILDCHAIN_UNIVERSAL_REQUEST_JSON: ${{ inputs.request-json }}
|
|
178
|
+
BUILDCHAIN_UNIVERSAL_ADMISSION_JSON: ${{ needs.recovery-admit.outputs.admission-json }}
|
|
179
|
+
BUILDCHAIN_UNIVERSAL_ENGINE_SHA: ${{ needs.recovery-admit.outputs.runtime-sha }}
|
|
180
|
+
GH_TOKEN: ${{ github.token }}
|
|
181
|
+
run: |
|
|
182
|
+
set -euo pipefail
|
|
183
|
+
node .buildchain/candidate/scripts/v4-universal-workflow-engine.mjs execute > .buildchain-result.json
|
|
184
|
+
echo "result-json=$(jq -c '.' .buildchain-result.json)" >> "${GITHUB_OUTPUT}"
|
|
185
|
+
|
|
186
|
+
recovery-settle:
|
|
187
|
+
needs: [recovery-admit, recovery-execute]
|
|
188
|
+
runs-on: ubuntu-24.04
|
|
189
|
+
permissions:
|
|
190
|
+
contents: read
|
|
191
|
+
issues: write
|
|
192
|
+
pull-requests: read
|
|
193
|
+
outputs:
|
|
194
|
+
terminal-receipt-json: ${{ steps.settle.outputs.terminal-receipt-json }}
|
|
195
|
+
terminal-receipt-root: ${{ steps.settle.outputs.terminal-receipt-root }}
|
|
196
|
+
backflow-root: ${{ steps.backflow.outputs.backflow-root }}
|
|
197
|
+
steps:
|
|
198
|
+
- name: Seal receipt outside candidate authority
|
|
199
|
+
id: settle
|
|
200
|
+
shell: bash
|
|
201
|
+
env:
|
|
202
|
+
BUILDCHAIN_UNIVERSAL_ADMISSION_JSON: ${{ needs.recovery-admit.outputs.admission-json }}
|
|
203
|
+
BUILDCHAIN_UNIVERSAL_RESULT_JSON: ${{ needs.recovery-execute.outputs.result-json }}
|
|
204
|
+
run: |
|
|
205
|
+
set -euo pipefail
|
|
206
|
+
node <<'NODE' > .buildchain-terminal.json
|
|
207
|
+
const crypto = require("node:crypto");
|
|
208
|
+
const admission = JSON.parse(process.env.BUILDCHAIN_UNIVERSAL_ADMISSION_JSON);
|
|
209
|
+
const result = JSON.parse(process.env.BUILDCHAIN_UNIVERSAL_RESULT_JSON);
|
|
210
|
+
const rootPattern = /^sha256:[0-9a-f]{64}$/;
|
|
211
|
+
const shaPattern = /^[0-9a-f]{40}$/;
|
|
212
|
+
const canonical = (value) => Array.isArray(value)
|
|
213
|
+
? value.map(canonical)
|
|
214
|
+
: value && typeof value === "object"
|
|
215
|
+
? Object.fromEntries(Object.keys(value).sort((left, right) => Buffer.from(left).compare(Buffer.from(right))).map((key) => [key, canonical(value[key])]))
|
|
216
|
+
: value;
|
|
217
|
+
const documentRoot = (domain, value) => {
|
|
218
|
+
const hash = crypto.createHash("sha256");
|
|
219
|
+
hash.update(domain, "utf8");
|
|
220
|
+
hash.update(Buffer.from([0]));
|
|
221
|
+
hash.update(`${JSON.stringify(canonical(value))}\n`, "utf8");
|
|
222
|
+
return `sha256:${hash.digest("hex")}`;
|
|
223
|
+
};
|
|
224
|
+
if (
|
|
225
|
+
admission.schema !== "kungfu-buildchain-v4-universal-workflow-admission/v1" ||
|
|
226
|
+
admission.status !== "admitted" ||
|
|
227
|
+
result.schema !== "kungfu-buildchain-v4-universal-workflow-result/v1" ||
|
|
228
|
+
!["succeeded", "failed"].includes(result.status) ||
|
|
229
|
+
result.requestRoot !== admission.requestRoot ||
|
|
230
|
+
result.capabilityRoot !== admission.capabilityRoot ||
|
|
231
|
+
result.runtime?.repository !== admission.runtime?.repository ||
|
|
232
|
+
result.runtime?.sha !== admission.runtime?.sha ||
|
|
233
|
+
!shaPattern.test(admission.runtime?.sha || "") ||
|
|
234
|
+
![
|
|
235
|
+
admission.requestRoot,
|
|
236
|
+
admission.admissionRoot,
|
|
237
|
+
admission.discoveryRoot,
|
|
238
|
+
admission.reviewRoot,
|
|
239
|
+
admission.consumerRoot,
|
|
240
|
+
admission.capabilityRoot,
|
|
241
|
+
result.resultRoot,
|
|
242
|
+
].every((value) => rootPattern.test(value || ""))
|
|
243
|
+
) throw new Error("candidate result does not match the consumer-owned admission lineage");
|
|
244
|
+
const receipt = {
|
|
245
|
+
schema: "kungfu-buildchain-v4-universal-workflow-terminal-receipt/v1",
|
|
246
|
+
status: result.status,
|
|
247
|
+
requestRoot: admission.requestRoot,
|
|
248
|
+
admissionRoot: admission.admissionRoot,
|
|
249
|
+
discoveryRoot: admission.discoveryRoot,
|
|
250
|
+
reviewRoot: admission.reviewRoot,
|
|
251
|
+
consumerRoot: admission.consumerRoot,
|
|
252
|
+
capabilityRoot: admission.capabilityRoot,
|
|
253
|
+
runtime: admission.runtime,
|
|
254
|
+
resultRoot: result.resultRoot,
|
|
255
|
+
};
|
|
256
|
+
process.stdout.write(`${JSON.stringify({ ...receipt, receiptRoot: documentRoot("universal-workflow-receipt", receipt) })}\n`);
|
|
257
|
+
NODE
|
|
258
|
+
{
|
|
259
|
+
echo "terminal-receipt-json=$(jq -c '.' .buildchain-terminal.json)"
|
|
260
|
+
echo "terminal-receipt-root=$(jq -r '.receiptRoot' .buildchain-terminal.json)"
|
|
261
|
+
} >> "${GITHUB_OUTPUT}"
|
|
262
|
+
test "$(jq -r '.status' <<< "${BUILDCHAIN_UNIVERSAL_RESULT_JSON}")" = "succeeded"
|
|
263
|
+
|
|
264
|
+
- name: Checkout exact reviewed backflow coordinator
|
|
265
|
+
uses: actions/checkout@v7.0.0
|
|
266
|
+
with:
|
|
267
|
+
repository: kungfu-systems/buildchain
|
|
268
|
+
ref: ${{ needs.recovery-admit.outputs.runtime-sha }}
|
|
269
|
+
path: .buildchain/candidate
|
|
270
|
+
persist-credentials: false
|
|
271
|
+
|
|
272
|
+
- name: Bind successful delivery to protected backflow
|
|
273
|
+
id: backflow
|
|
274
|
+
shell: bash
|
|
275
|
+
env:
|
|
276
|
+
BUILDCHAIN_UNIVERSAL_REQUEST_JSON: ${{ inputs.request-json }}
|
|
277
|
+
BUILDCHAIN_UNIVERSAL_TERMINAL_RECEIPT_JSON: ${{ steps.settle.outputs.terminal-receipt-json }}
|
|
278
|
+
GH_TOKEN: ${{ github.token }}
|
|
279
|
+
run: |
|
|
280
|
+
set -euo pipefail
|
|
281
|
+
node .buildchain/candidate/scripts/v4-universal-workflow-backflow.mjs > .buildchain-backflow.json
|
|
282
|
+
echo "backflow-root=$(jq -r '.backflowRoot // empty' .buildchain-backflow.json)" >> "${GITHUB_OUTPUT}"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Universal Buildchain Bootstrap
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
request-json:
|
|
7
|
+
description: "Versioned exact-candidate request envelope"
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
outputs:
|
|
11
|
+
runtime-sha:
|
|
12
|
+
value: ${{ jobs.bootstrap.outputs.runtime-sha }}
|
|
13
|
+
terminal-receipt-json:
|
|
14
|
+
value: ${{ jobs.bootstrap.outputs.terminal-receipt-json }}
|
|
15
|
+
terminal-receipt-root:
|
|
16
|
+
value: ${{ jobs.bootstrap.outputs.terminal-receipt-root }}
|
|
17
|
+
backflow-root:
|
|
18
|
+
value: ${{ jobs.bootstrap.outputs.backflow-root }}
|
|
19
|
+
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
bootstrap:
|
|
25
|
+
uses: kungfu-systems/buildchain/.github/workflows/bootstrap.yml@v4
|
|
26
|
+
with:
|
|
27
|
+
request-json: ${{ inputs.request-json }}
|
|
28
|
+
secrets: inherit
|