@kungfu-tech/buildchain 4.0.8 → 4.0.9-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -19
- package/CONTRIBUTING.md +6 -9
- package/README.md +11 -1
- package/architecture/agent-change-map.md +11 -4
- package/architecture/build-environments.json +71 -0
- package/architecture/build-orchestration.json +18 -0
- package/architecture/ci-lane-change-budget.json +34 -2
- package/architecture/internal-capabilities.json +17 -4
- package/architecture/maintainability-debt.json +34 -123
- package/architecture/maintainability-policy.json +19 -210
- package/architecture/release-topology.json +6 -5
- package/architecture/universal-workflow-bootstrap.json +5 -4
- package/architecture/universal-workflow-train-admission.json +2 -2
- package/bin/buildchain.mjs +1 -1
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/dist/site/buildchain-contract.json +41 -1131
- package/dist/site/buildchain-site.json +39 -144
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/cli-registry.json +1 -1
- package/dist/site/controller-registry.json +30 -868
- package/dist/site/kfd-claims.json +132 -394
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +6 -6
- package/dist/site/node-api-registry.json +34 -34
- package/dist/site/page-registry.json +30 -135
- package/dist/site/public-surface-audit.json +81 -401
- package/dist/site/publication-registry.json +2 -2
- package/dist/site/site-manifest.json +8 -8
- package/dist/site/workflow-registry.json +135 -391
- package/docs/MAP.md +5 -4
- package/docs/cli-reference.md +1 -1
- package/docs/getting-started.md +8 -7
- package/docs/node-api-reference.md +79 -79
- package/docs/reusable-build-surface.md +159 -1430
- package/docs/runtime-train-validation.md +45 -172
- package/package.json +1 -1
- package/packages/core/build-configuration.js +117 -0
- package/packages/core/buildchain-config.js +2 -0
- package/packages/core/buildchain-contract.js +14 -44
- package/packages/core/controller-evidence.js +2 -9
- package/scripts/buildchain-cli-help.mjs +1 -1
- package/scripts/check-floating-consumer-policy-contract.mjs +4 -7
- package/scripts/check-inventory.mjs +81 -54
- package/scripts/check-universal-workflow-bootstrap.mjs +12 -2
- package/scripts/generate-channel-build-workflow.mjs +50 -410
- package/scripts/generate-site-bundle.mjs +2 -1
- package/scripts/generate-universal-workflow-facades.mjs +1 -0
- package/scripts/init-repo.mjs +25 -26
- package/scripts/resolve-build-configuration.mjs +105 -0
- package/scripts/universal-workflow-self-dogfood.mjs +8 -1
- package/scripts/verify-golden-path.mjs +3 -3
|
@@ -6,1463 +6,192 @@ doc_type: technical-reference
|
|
|
6
6
|
source_level: local-files
|
|
7
7
|
confidence: high
|
|
8
8
|
sensitivity: public
|
|
9
|
-
evidence_grade:
|
|
9
|
+
evidence_grade: B
|
|
10
10
|
review_state: unreviewed
|
|
11
|
-
last_reviewed: 2026-08
|
|
11
|
+
last_reviewed: 2026-09-08
|
|
12
12
|
ai_provenance:
|
|
13
|
-
model_family: GPT-
|
|
13
|
+
model_family: GPT-6
|
|
14
14
|
product: Codex
|
|
15
|
-
generated_at: 2026-08
|
|
16
|
-
|
|
15
|
+
generated_at: 2026-09-08
|
|
16
|
+
invisible_context_boundary: No private credentials or unrelated repositories inspected.
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
# Reusable Build Surface
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
systems, self-hosted runner labels, and release artifacts that must be auditable.
|
|
25
|
-
|
|
26
|
-
For Linux release artifacts, the build workflow can hand the sealed artifact,
|
|
27
|
-
platform manifest, and Release Passport to the separate GitHub-hosted keyless
|
|
28
|
-
attester. The compiler runner remains the recorded build identity; the attester
|
|
29
|
-
only signs and verifies immutable data. See
|
|
30
|
-
[`github-artifact-attestation.md`](github-artifact-attestation.md).
|
|
31
|
-
|
|
32
|
-
## Automatic Channel Router
|
|
33
|
-
|
|
34
|
-
The preferred consumer surface is one reusable workflow call. Consumers keep
|
|
35
|
-
this configuration for both alpha development and stable release work:
|
|
36
|
-
|
|
37
|
-
```yaml
|
|
38
|
-
jobs:
|
|
39
|
-
build:
|
|
40
|
-
uses: kungfu-systems/buildchain/.github/workflows/build.yml@v3
|
|
41
|
-
permissions:
|
|
42
|
-
contents: read
|
|
43
|
-
issues: write
|
|
44
|
-
id-token: write
|
|
45
|
-
with:
|
|
46
|
-
working-directory: .
|
|
47
|
-
artifact-name: libnode
|
|
48
|
-
runner-preset: kungfu-v4-self-hosted
|
|
49
|
-
publish-channel: none
|
|
50
|
-
secrets: inherit
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
`buildchain-channel` defaults to `auto`. Selection uses this precedence:
|
|
54
|
-
|
|
55
|
-
1. an explicit `buildchain-ref` protected authority, train, SHA, or official channel;
|
|
56
|
-
2. an explicit `buildchain-channel: alpha|stable`;
|
|
57
|
-
3. `publish-channel: alpha|release|major`;
|
|
58
|
-
4. GitHub release prerelease metadata;
|
|
59
|
-
5. a canonical semver tag;
|
|
60
|
-
6. non-release PR, push, dispatch, schedule, and workflow-run events default to
|
|
61
|
-
alpha.
|
|
62
|
-
|
|
63
|
-
The resolved runtime is `vN-alpha` for development and prerelease intent and
|
|
64
|
-
`vN` for stable release intent. Unknown custom publish channels, malformed
|
|
65
|
-
release events, and non-semver release-like tags fail before the build matrix;
|
|
66
|
-
they never guess alpha for a stable release.
|
|
67
|
-
|
|
68
|
-
The router automatically selects `.buildchain/alpha-contract-lock.json` for
|
|
69
|
-
alpha and `.buildchain/contract-lock.json` for stable. The generated workflow
|
|
70
|
-
uses two static advanced-workflow calls: `@vN-alpha` for alpha and `@vN` for
|
|
71
|
-
stable. A repository can override the common path with
|
|
72
|
-
`buildchain-contract-lock-path`, or override one channel with
|
|
73
|
-
`buildchain-alpha-contract-lock-path` / `buildchain-stable-contract-lock-path`,
|
|
74
|
-
but the path is never channel authority. The selected file's
|
|
75
|
-
`buildchain.ref` must prove the same channel and major as the workflow shell and
|
|
76
|
-
runtime.
|
|
77
|
-
|
|
78
|
-
Channel binding is independent of the current Buildchain major. Every
|
|
79
|
-
channel-bound run validates the complete triad before compatibility drift:
|
|
80
|
-
|
|
81
|
-
- stable = shell `vN` + runtime `vN` + a lock whose ref is stable `vN`;
|
|
82
|
-
- alpha = shell `vN-alpha` + runtime `vN-alpha` + a lock whose ref is alpha
|
|
83
|
-
`vN-alpha`.
|
|
84
|
-
|
|
85
|
-
Exact release refs are classified the same way. A missing lock, an ambiguous
|
|
86
|
-
identity, a major mismatch, or any stable/alpha mixture fails even when the
|
|
87
|
-
contract digest is unchanged or the drift would otherwise be additive.
|
|
88
|
-
|
|
89
|
-
Only repositories changing the default policy need extra routing input:
|
|
90
|
-
|
|
91
|
-
```yaml
|
|
92
|
-
with:
|
|
93
|
-
buildchain-channel: stable
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
During v3 prerelease evaluation windows, canaries use `build.yml@v3-alpha`.
|
|
97
|
-
The same router then selects `v3-alpha` or stable `v3` as the runtime.
|
|
98
|
-
Production consumers use `build.yml@v3`; this keeps the routing shell itself on
|
|
99
|
-
a stable ref.
|
|
100
|
-
|
|
101
|
-
The router is generated from `.build.yml`'s input/output surface. Run
|
|
102
|
-
`node scripts/generate-channel-build-workflow.mjs` after changing the advanced
|
|
103
|
-
build workflow; inventory and unit tests reject a stale generated router.
|
|
104
|
-
|
|
105
|
-
### v4 floating consumer admission
|
|
106
|
-
|
|
107
|
-
The v4 public surfaces add a source policy gate before dependency setup, matrix
|
|
108
|
-
planning, build, publication, or promotion work. Tracked caller YAML may use
|
|
109
|
-
only `@v4` or `@v4-alpha`, and the repository must commit both
|
|
110
|
-
`.buildchain/contract-lock.json` and `.buildchain/alpha-contract-lock.json`.
|
|
111
|
-
Source-persisted exact SHAs, exact defaults, repository/input/environment
|
|
112
|
-
indirection, nested composite indirection, a missing lock, or a stale selected
|
|
113
|
-
lock fail closed.
|
|
114
|
-
|
|
115
|
-
Admission emits a rooted receipt binding the caller source, public workflow,
|
|
116
|
-
visible selector and workflow-shell SHA, actual runtime SHA, both lock roots,
|
|
117
|
-
and policy/scanner roots. A trusted `workflow_dispatch` train or SHA remains a
|
|
118
|
-
non-persistent runtime override: the tracked floating selector and its selected
|
|
119
|
-
lock still bind the visible workflow shell. Release-candidate evidence carries
|
|
120
|
-
the receipt; promotion certifies it independently; final v4 Release Passport
|
|
121
|
-
construction requires the matching certification.
|
|
122
|
-
|
|
123
|
-
Transient train, authority, and exact-SHA selections additionally produce a
|
|
124
|
-
provider-readback-bound runtime authorization receipt. A resumed failed tail
|
|
125
|
-
uses a fresh attempt and records the original build runtime, the resume runtime,
|
|
126
|
-
the exact sealed Stage Capsules reused per platform, and the platforms rebuilt
|
|
127
|
-
in the final Release Passport. See
|
|
128
|
-
[`v4-runtime-ref-resume-authority.md`](v4-runtime-ref-resume-authority.md).
|
|
129
|
-
|
|
130
|
-
See the normative
|
|
131
|
-
[`v4 floating consumer policy`](../architecture/floating-consumer-policy.md)
|
|
132
|
-
and its machine declaration for the exact acceptance boundary. This policy does
|
|
133
|
-
not change v3 behavior.
|
|
134
|
-
|
|
135
|
-
### Universal Bootstrap verified-caller admission
|
|
136
|
-
|
|
137
|
-
The v4 Universal Bootstrap does not maintain a repository allowlist. Any
|
|
138
|
-
repository that can call the public reusable workflow may submit the single
|
|
139
|
-
versioned request envelope. Admission still fails closed unless the request's
|
|
140
|
-
consumer repository, caller workflow path, and source SHA exactly match the
|
|
141
|
-
GitHub-observed caller context.
|
|
142
|
-
|
|
143
|
-
Open consumer admission does not mean open execution authority. The candidate
|
|
144
|
-
must still be an exact Buildchain SHA selected through a governed discovery
|
|
145
|
-
ref, bind the current candidate-owned admission root, have exact-head
|
|
146
|
-
independent review and required checks, request an admitted capability and
|
|
147
|
-
contract-root set, stay within the permission ceiling and validity window, and
|
|
148
|
-
inherit only authority available from the caller. The candidate engine exposes
|
|
149
|
-
bounded capability adapters; it does not accept caller-provided shell or code.
|
|
150
|
-
|
|
151
|
-
## Advanced Workflow
|
|
152
|
-
|
|
153
|
-
Consumers that need direct workflow-shell or runtime control call the advanced
|
|
154
|
-
surface:
|
|
21
|
+
A project declares its build in `buildchain.toml`. The reusable workflow owns
|
|
22
|
+
job sequencing, admission, runner boundaries and evidence aggregation. Ordinary
|
|
23
|
+
single-project calls have no inputs:
|
|
155
24
|
|
|
156
25
|
```yaml
|
|
26
|
+
permissions:
|
|
27
|
+
actions: read
|
|
28
|
+
contents: read
|
|
29
|
+
issues: write
|
|
30
|
+
id-token: write
|
|
157
31
|
jobs:
|
|
158
32
|
build:
|
|
159
|
-
uses: kungfu-systems/buildchain/.github/workflows
|
|
160
|
-
with:
|
|
161
|
-
working-directory: .
|
|
162
|
-
artifact-name: libnode
|
|
163
|
-
runner-preset: kungfu-v4-self-hosted
|
|
164
|
-
linux-container-preset: kungfu-verify
|
|
165
|
-
artifact-name-template: "{artifact}-{platform}-{sha}"
|
|
166
|
-
artifact-paths: |
|
|
167
|
-
dist
|
|
168
|
-
build/stage
|
|
169
|
-
pre-upload-transport-smoke-scenario-path: .buildchain/auditable-demo.json
|
|
170
|
-
pre-upload-transport-smoke-artifact-root: .
|
|
171
|
-
expected-artifacts-json: >-
|
|
172
|
-
{"minFiles":2,"requiredPaths":["dist/libnode.tar.gz","dist/checksums.txt"]}
|
|
173
|
-
process-summary-path: .buildchain/diagnostics/process-summary.json
|
|
174
|
-
release-candidate: true
|
|
175
|
-
publish-channel: release
|
|
176
|
-
publish-source-ref: publish-gate/release/v22/v22.22/22.22.3-kf.0
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
For a standalone Linux binary demo, the optional pre-upload transport smoke
|
|
180
|
-
uses the same declarative scenario as the later capture workflow. Buildchain
|
|
181
|
-
copies the distribution containing the scenario metadata, strips file execute
|
|
182
|
-
bits to model GitHub Artifact transport, restores only the declared
|
|
183
|
-
digest-bound executable closure, and runs `transportSmoke` before either the
|
|
184
|
-
GitHub Artifact or S3 relay upload step. The smoke must be non-interactive and
|
|
185
|
-
is hard-capped at 60 seconds. Omitting the input preserves the ordinary build
|
|
186
|
-
surface; enabling it requires a scenario with `transportSmoke`.
|
|
187
|
-
|
|
188
|
-
`runner-preset` is the stable first-class surface for known runner fleets:
|
|
189
|
-
|
|
190
|
-
| Preset | Platforms |
|
|
191
|
-
| ----------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
192
|
-
| `github-hosted` | `ubuntu-24.04`, `macos-latest`, `windows-2022` |
|
|
193
|
-
| `kungfu-v4-self-hosted` | Kungfu Linux x64, macOS ARM64, and Windows x64 self-hosted runner labels |
|
|
194
|
-
| `kungfu-v4-native` | Kungfu Linux x64, Linux ARM64, macOS ARM64, and Windows x64; Linux ARM64 uses GitHub-hosted `ubuntu-24.04-arm` |
|
|
195
|
-
| `custom` | Requires `platforms-json` |
|
|
196
|
-
|
|
197
|
-
Set `self-hosted-offline-fallback: true` to inspect every exact-label
|
|
198
|
-
self-hosted lane from the trusted Buildchain workflow shell before the matrix
|
|
199
|
-
starts. A lane with no matching online runner is replaced independently by its
|
|
200
|
-
supported GitHub-hosted runner: Kungfu Linux x64 uses `ubuntu-24.04`, macOS ARM64
|
|
201
|
-
uses `macos-15`, and Windows x64 uses `windows-2022`. Online-but-busy runners
|
|
202
|
-
remain online and keep their declared self-hosted route. Organization-owned
|
|
203
|
-
repositories inspect organization runner inventory so selected-repository runner
|
|
204
|
-
groups are not mistaken for an empty repository runner inventory. If the
|
|
205
|
-
inventory token, permission, or API is unavailable, Buildchain preserves the
|
|
206
|
-
original matrix instead of guessing that the fleet is offline. The public
|
|
207
|
-
workflow output `runner-routing-json` records only de-identified counts,
|
|
208
|
-
inventory scope, and routing decisions.
|
|
209
|
-
|
|
210
|
-
```yaml
|
|
211
|
-
with:
|
|
212
|
-
runner-preset: kungfu-v4-native
|
|
213
|
-
self-hosted-offline-fallback: true
|
|
214
|
-
secrets:
|
|
215
|
-
BUILDCHAIN_PROMOTION_TOKEN: ${{ secrets.KUNGFU_GITHUB_TOKEN }}
|
|
33
|
+
uses: kungfu-systems/buildchain/.github/workflows/build.yml@v4
|
|
216
34
|
```
|
|
217
35
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
| `id` | Stable artifact/platform key, such as `linux-x64` |
|
|
224
|
-
| `name` | Human-readable job name |
|
|
225
|
-
| `runner` | JSON string passed to `runs-on` after `fromJSON` |
|
|
226
|
-
|
|
227
|
-
The runner field is intentionally a JSON string so callers can pass either
|
|
228
|
-
GitHub-hosted runners or multi-label self-hosted runners without Buildchain
|
|
229
|
-
guessing the labels.
|
|
36
|
+
Use `@v4-alpha` to select the alpha runtime. The exact called workflow SHA is
|
|
37
|
+
the runtime SHA; a second runtime selector cannot override it. Both the public
|
|
38
|
+
`build.yml` and the `.build.yml` backbone expose exactly one optional input:
|
|
39
|
+
`config-path`. Neither accepts command overrides, runtime refs, arbitrary JSON
|
|
40
|
+
configuration or legacy aliases.
|
|
230
41
|
|
|
231
|
-
|
|
232
|
-
steps execute, so a disabled entry with unavailable runner labels can still
|
|
233
|
-
block the workflow queue.
|
|
42
|
+
## Project discovery
|
|
234
43
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
failure. This input changes scheduling only: it does not reduce the declared
|
|
239
|
-
platform matrix, turn cancellation into a pass, or alter artifact and release
|
|
240
|
-
admission.
|
|
241
|
-
|
|
242
|
-
## Linux Job Containers
|
|
243
|
-
|
|
244
|
-
Linux build platforms can run inside a digest-pinned job container while macOS
|
|
245
|
-
and Windows keep using native runners. This is the recommended way to remove
|
|
246
|
-
moving Linux runner prerequisites from Buildchain consumers: the Linux host only
|
|
247
|
-
needs a GitHub Actions runner, Docker, and network access; common verification
|
|
248
|
-
tools come from the image contract.
|
|
249
|
-
|
|
250
|
-
Use the Kungfu verification image for lifecycle stages that need Git, jq,
|
|
251
|
-
Python, uv, and fnm, but do not need native compilation:
|
|
44
|
+
At the repository root, exactly one of `.buildchain/buildchain.toml` and
|
|
45
|
+
`buildchain.toml` must exist. Missing or ambiguous configurations fail before
|
|
46
|
+
matrix scheduling. A nested project is selected with its configuration location:
|
|
252
47
|
|
|
253
48
|
```yaml
|
|
254
49
|
jobs:
|
|
255
|
-
|
|
256
|
-
uses: kungfu-systems/buildchain/.github/workflows
|
|
50
|
+
native:
|
|
51
|
+
uses: kungfu-systems/buildchain/.github/workflows/build.yml@v4-alpha
|
|
257
52
|
with:
|
|
258
|
-
|
|
259
|
-
linux-container-preset: kungfu-verify
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
`kungfu-verify` resolves to:
|
|
263
|
-
|
|
264
|
-
```text
|
|
265
|
-
ghcr.io/kungfu-systems/build-images/kungfu-verify@sha256:11f0ba64267ce88174a4f73a9bf833ff4e9c59cd16ec3d08a6432a06c2be6fb1
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
Callers that own a different Linux image can pass it explicitly:
|
|
269
|
-
|
|
270
|
-
```yaml
|
|
271
|
-
with:
|
|
272
|
-
linux-container-preset: custom
|
|
273
|
-
linux-container-image: ghcr.io/example/project-build@sha256:<digest>
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
`linux-container-image` should be pinned by digest. A floating tag makes the
|
|
277
|
-
runner surface mutable and weakens Buildchain's release evidence.
|
|
278
|
-
|
|
279
|
-
The workflow splits the matrix into two build jobs:
|
|
280
|
-
|
|
281
|
-
- Linux platforms go to `build-linux-container` when a Linux container is
|
|
282
|
-
configured.
|
|
283
|
-
- All other platforms go to `build-native`.
|
|
284
|
-
|
|
285
|
-
Artifact names, manifest paths, expected artifact checks, publish-source locks,
|
|
286
|
-
and aggregate summaries are the same in both jobs. The split is an execution
|
|
287
|
-
detail, not a different artifact contract.
|
|
288
|
-
|
|
289
|
-
## Native Rust Toolchains
|
|
290
|
-
|
|
291
|
-
Native lifecycle jobs can request an isolated Rust installation instead of
|
|
292
|
-
depending on a self-hosted runner user's PATH:
|
|
293
|
-
|
|
294
|
-
```yaml
|
|
295
|
-
with:
|
|
296
|
-
setup-rust: true
|
|
297
|
-
rust-toolchain: "1.96.0"
|
|
298
|
-
rustup-dist-server: "https://rsproxy.cn"
|
|
299
|
-
rustup-update-root: "https://rsproxy.cn/rustup"
|
|
300
|
-
cargo-registry-index: ${{ vars.BUILDCHAIN_CARGO_REGISTRY_INDEX }}
|
|
53
|
+
config-path: packages/native/.buildchain/buildchain.toml
|
|
301
54
|
```
|
|
302
55
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
Cargo and rustup homes, so it works under a restrictive PowerShell execution
|
|
308
|
-
policy and the service account does not depend on another user's PATH or mutate
|
|
309
|
-
host toolchain state. Pin an exact toolchain for release builds. Linux container jobs continue
|
|
310
|
-
to obtain Rust from their digest-pinned image contract; Buildchain does not
|
|
311
|
-
mutate that container surface.
|
|
312
|
-
|
|
313
|
-
The rustup server inputs are optional and default to Rust's official servers.
|
|
314
|
-
Consumers behind a slow cross-border link may select a trusted transport mirror;
|
|
315
|
-
rustup still verifies the selected toolchain's distribution metadata and
|
|
316
|
-
component checksums.
|
|
317
|
-
|
|
318
|
-
`cargo-registry-index` is also optional. When set, Buildchain exposes it to
|
|
319
|
-
Cargo as `CARGO_REGISTRIES_CRATES_IO_INDEX` for every native lifecycle stage,
|
|
320
|
-
so a self-hosted runner can use a repository or organization variable without
|
|
321
|
-
committing private LAN topology to public workflow YAML. The endpoint must be a
|
|
322
|
-
crates.io-compatible index whose `config.json` download contract serves the
|
|
323
|
-
matching checksum-verified crate archives. An empty value preserves Cargo's
|
|
324
|
-
normal crates.io behavior.
|
|
325
|
-
|
|
326
|
-
The container image provides `fnm` but does not preinstall Node. Buildchain uses
|
|
327
|
-
`fnm` inside the container to install the requested `node-version` before it
|
|
328
|
-
runs Buildchain runtime scripts or lifecycle actions.
|
|
329
|
-
|
|
330
|
-
Do not use `kungfu-verify` for stages that need CMake, Ninja, ccache, Conan, or
|
|
331
|
-
Docker image publishing. Those should use a heavier native-build image or remain
|
|
332
|
-
on a host runner until their image contract is explicit.
|
|
56
|
+
The config location determines the project working directory. Planning and
|
|
57
|
+
lifecycle execution discover the same file. Absolute paths, parent traversal,
|
|
58
|
+
symlink escape, malformed TOML and unknown `[build]` keys fail closed. A
|
|
59
|
+
configuration locator cannot carry a profile override or execution authority.
|
|
333
60
|
|
|
334
|
-
##
|
|
335
|
-
|
|
336
|
-
Stable consumers should keep the reusable workflow pinned to stable refs such as
|
|
337
|
-
`@v3`. The optional `buildchain-ref` input is empty by default; empty means
|
|
338
|
-
Buildchain resolves and executes the stable runtime selected by the workflow
|
|
339
|
-
shell. The full train validation protocol is documented in
|
|
340
|
-
[`runtime-train-validation.md`](runtime-train-validation.md).
|
|
341
|
-
|
|
342
|
-
For one-off manual validation, a trusted maintainer can run the caller workflow
|
|
343
|
-
with a temporary runtime override. The override inherits the caller's declared
|
|
344
|
-
alpha or stable lane; trust authorizes the opaque ref, not cross-channel use:
|
|
345
|
-
|
|
346
|
-
```yaml
|
|
347
|
-
on:
|
|
348
|
-
workflow_dispatch:
|
|
349
|
-
inputs:
|
|
350
|
-
buildchain-ref:
|
|
351
|
-
description: "Temporary Buildchain runtime ref for trusted manual validation"
|
|
352
|
-
required: false
|
|
353
|
-
default: ""
|
|
354
|
-
|
|
355
|
-
jobs:
|
|
356
|
-
build:
|
|
357
|
-
uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
|
|
358
|
-
with:
|
|
359
|
-
buildchain-ref: ${{ inputs.buildchain-ref || '' }}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
Allowed override refs are deliberately narrow:
|
|
363
|
-
|
|
364
|
-
| Ref form | Meaning |
|
|
365
|
-
| --------------------------------------- | ------------------------------------------------------ |
|
|
366
|
-
| `train/v3/v3.0/<capability>` | Temporary capability train under the active minor line |
|
|
367
|
-
| `refs/heads/train/v3/v3.0/<capability>` | Explicit branch ref for the same train |
|
|
368
|
-
| `<40-character SHA>` | Exact immutable Buildchain runtime commit |
|
|
369
|
-
|
|
370
|
-
Override requests fail closed unless the event is `workflow_dispatch` and the
|
|
371
|
-
actor has write, maintain, or admin permission on the caller repository. One
|
|
372
|
-
non-override exact-pin case is also admitted: when the reusable workflow itself
|
|
373
|
-
is invoked from an exact Buildchain SHA and `buildchain-ref` names that identical
|
|
374
|
-
SHA, the run records `pinned-self`. The input cannot select code other than the
|
|
375
|
-
already-running workflow shell, so protected push and pull-request publication
|
|
376
|
-
jobs can retain one immutable runtime root. Different SHA and train requests
|
|
377
|
-
still fail closed outside trusted manual dispatch.
|
|
378
|
-
|
|
379
|
-
Pull requests, including same-repository pull requests and fork-originated pull
|
|
380
|
-
requests, cannot select an independent `buildchain-ref` override. This keeps
|
|
381
|
-
automated PR builds on the stable or exact pinned-self runtime surface.
|
|
382
|
-
|
|
383
|
-
Every run resolves the runtime ref to an immutable SHA before checkout. The job
|
|
384
|
-
summary and aggregate build summary record the workflow shell ref, requested
|
|
385
|
-
runtime ref, resolved runtime ref, runtime SHA, stability class, trust decision,
|
|
386
|
-
and rollback ref. Train refs are development validation refs: they do not move
|
|
387
|
-
`v3`, `vX.Y`, `vX.Y-alpha`, npm dist-tags, or production release refs, and they
|
|
388
|
-
must not be pinned as long-term production dependencies.
|
|
389
|
-
|
|
390
|
-
Runtime override validates Buildchain runtime scripts, CLI code, local actions,
|
|
391
|
-
config parsing, and lifecycle behavior. It cannot validate changes that require
|
|
392
|
-
the outer reusable workflow YAML itself to change, such as new jobs,
|
|
393
|
-
permissions, workflow outputs, or matrix topology. Those changes need a canary
|
|
394
|
-
workflow path or a temporary explicit workflow ref.
|
|
395
|
-
|
|
396
|
-
## Floating Ref Contract Lock
|
|
397
|
-
|
|
398
|
-
Stable consumers should use floating major refs such as `@v3`, but a floating
|
|
399
|
-
ref is not blind trust. Each released Buildchain ref carries a package-owned
|
|
400
|
-
runtime contract world in `dist/site/buildchain-contract.json`. Consumers may
|
|
401
|
-
keep a small lock file, `.buildchain/contract-lock.json`, recording the
|
|
402
|
-
Buildchain ref, resolved SHA, contract digest, compatibility digest, accepted
|
|
403
|
-
major line, and compatibility policy they reviewed.
|
|
404
|
-
|
|
405
|
-
The reusable build trust gate checks this lock before any heavy matrix job:
|
|
406
|
-
|
|
407
|
-
1. resolve the Buildchain runtime ref, for example `v3`, to an immutable SHA;
|
|
408
|
-
2. read `dist/site/buildchain-contract.json` from that checked-out Buildchain
|
|
409
|
-
ref;
|
|
410
|
-
3. read the consumer's `.buildchain/contract-lock.json`;
|
|
411
|
-
4. compare the accepted contract with the current contract.
|
|
412
|
-
|
|
413
|
-
SHA drift alone is not a failure. `v3` is expected to advance. Buildchain only
|
|
414
|
-
fails fast when the accepted contract is no longer compatible, for example a
|
|
415
|
-
required input is removed, a required output disappears, a protected behavior
|
|
416
|
-
promise changes, or the major line changes. Additive changes such as optional
|
|
417
|
-
inputs, optional outputs, diagnostics, or documentation updates continue under
|
|
418
|
-
the default `major-compatible` policy.
|
|
419
|
-
|
|
420
|
-
```yaml
|
|
421
|
-
jobs:
|
|
422
|
-
build:
|
|
423
|
-
uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
|
|
424
|
-
permissions:
|
|
425
|
-
contents: read
|
|
426
|
-
issues: write
|
|
427
|
-
id-token: write
|
|
428
|
-
with:
|
|
429
|
-
buildchain-contract-lock-path: .buildchain/contract-lock.json
|
|
430
|
-
buildchain-contract-compatibility-policy: major-compatible
|
|
431
|
-
buildchain-contract-drift-issue-mode: compatible-and-breaking
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
When compatible drift is detected, the build continues and Buildchain opens or
|
|
435
|
-
updates a low-priority issue in the consumer repository. The issue records the
|
|
436
|
-
old SHA/digest, new SHA/digest, compatibility result, workflow run, and the next
|
|
437
|
-
action: review the Buildchain release notes and update the lock. When breaking
|
|
438
|
-
drift is detected, the same issue path is used, but the trust gate fails before
|
|
439
|
-
matrix build or publish work starts. If the workflow token cannot write issues,
|
|
440
|
-
Buildchain writes a copyable issue body into the job summary.
|
|
441
|
-
|
|
442
|
-
The lock is intentionally small. It does not copy the full contract. The full
|
|
443
|
-
contract remains in the Buildchain ref and package; the consumer records only
|
|
444
|
-
what it accepted and the policy used to compare future floating-ref movement.
|
|
445
|
-
|
|
446
|
-
Advanced alpha-channel consumers select the matching workflow shell:
|
|
447
|
-
|
|
448
|
-
```yaml
|
|
449
|
-
jobs:
|
|
450
|
-
build:
|
|
451
|
-
uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3-alpha
|
|
452
|
-
with:
|
|
453
|
-
buildchain-contract-lock-path: .buildchain/contract-lock.json
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
The runtime follows the called workflow through `job.workflow_ref`. Callers may
|
|
457
|
-
also pass `buildchain-ref: v3-alpha` explicitly; official floating refs are
|
|
458
|
-
ordinary channel selections and are allowed on pull requests and pushes. Train
|
|
459
|
-
refs and exact SHAs remain trusted manual overrides.
|
|
460
|
-
|
|
461
|
-
## Shifu Cache Profile Passthrough
|
|
462
|
-
|
|
463
|
-
Buildchain can carry one trusted Shifu cache-profile reference and its exact
|
|
464
|
-
digest into lifecycle execution. Its contract is an opaque reference and digest
|
|
465
|
-
only. This surface is deliberately opaque:
|
|
466
|
-
Buildchain does not fetch the profile, parse JSON, select cache services,
|
|
467
|
-
rewrite bindings, decide fallback, or emit Shifu resolution evidence. Those
|
|
468
|
-
semantics remain owned by the consumer's pinned Shifu implementation.
|
|
469
|
-
|
|
470
|
-
```yaml
|
|
471
|
-
jobs:
|
|
472
|
-
build:
|
|
473
|
-
uses: kungfu-systems/buildchain/.github/workflows/build.yml@v3
|
|
474
|
-
with:
|
|
475
|
-
shifu-cache-profile-ref: ${{ vars.SHIFU_CACHE_PROFILE_REF }}
|
|
476
|
-
shifu-cache-profile-digest: ${{ vars.SHIFU_CACHE_PROFILE_DIGEST }}
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
The reusable workflow passes the pair as `SHIFU_CACHE_PROFILE_REF` and
|
|
480
|
-
`SHIFU_CACHE_PROFILE_DIGEST` to install, build, and verify lifecycle commands.
|
|
481
|
-
The consumer must invoke its Shifu cache-aware execution surface. An empty pair
|
|
482
|
-
preserves existing behavior; a consumer Shifu should fail closed when exactly
|
|
483
|
-
one value is present or the resolved bytes do not match the expected digest.
|
|
484
|
-
|
|
485
|
-
Use trusted repository or organization variables rather than PR-controlled
|
|
486
|
-
files for private/LAN references. The variables must remain secret-free; any
|
|
487
|
-
credentials use a separate provider-approved secret surface and must not be
|
|
488
|
-
embedded in the profile reference. This passthrough is separate from
|
|
489
|
-
Buildchain's locked source checkout cache below: Buildchain owns checkout
|
|
490
|
-
transport and source identity, while Shifu owns post-checkout execution cache
|
|
491
|
-
bindings and receipts.
|
|
492
|
-
|
|
493
|
-
## Locked Source Checkout Cache
|
|
494
|
-
|
|
495
|
-
Self-hosted runners that build large repositories can opt into a locked checkout
|
|
496
|
-
cache for both the consumer source and the Buildchain runtime. This changes only
|
|
497
|
-
the Git object transport. Buildchain still resolves `publish-source-sha` and the
|
|
498
|
-
runtime SHA before any build runner starts, checks out those exact commits, and
|
|
499
|
-
verifies each final `HEAD` plus the resolved consumer source tree SHA before
|
|
500
|
-
lifecycle commands run.
|
|
501
|
-
|
|
502
|
-
```yaml
|
|
503
|
-
jobs:
|
|
504
|
-
build:
|
|
505
|
-
uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
|
|
506
|
-
with:
|
|
507
|
-
runner-preset: kungfu-v4-self-hosted
|
|
508
|
-
checkout-cache-mode: auto
|
|
509
|
-
checkout-cache-mirror-url-template: ${{ vars.BUILDCHAIN_CHECKOUT_CACHE_MIRROR_URL_TEMPLATE }}
|
|
510
|
-
checkout-cache-reference-repository-template: ${{ vars.BUILDCHAIN_CHECKOUT_CACHE_REFERENCE_REPOSITORY_TEMPLATE }}
|
|
511
|
-
checkout-cache-fallback: github
|
|
512
|
-
checkout-cache-timeout-seconds: 60
|
|
513
|
-
checkout-cache-github-timeout-seconds: 600
|
|
514
|
-
checkout-cache-fetch-attempts: 3
|
|
515
|
-
checkout-history-mode: shallow
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
`checkout-cache-mode` accepts:
|
|
519
|
-
|
|
520
|
-
| Mode | Behavior |
|
|
521
|
-
| --------- | ----------------------------------------------------------------------------------------------------------- |
|
|
522
|
-
| `off` | Default. Buildchain fetches the locked commit from GitHub. |
|
|
523
|
-
| `auto` | Try the trusted cache first; on miss, record the miss and fall back according to `checkout-cache-fallback`. |
|
|
524
|
-
| `require` | Require the cache to provide the locked commit and fail before lifecycle work if unavailable. |
|
|
525
|
-
|
|
526
|
-
`checkout-history-mode` defaults to `shallow`, preserving the bounded single-
|
|
527
|
-
commit transport used by ordinary builds. Set it to `full` only when a
|
|
528
|
-
consumer gate must inspect source ancestry, for example when an Alpha pull
|
|
529
|
-
request qualifies GitHub's synthetic merge ref while retained evidence is
|
|
530
|
-
bound to an ancestor of the source-lock head. Full mode still verifies the
|
|
531
|
-
resolved immutable `HEAD` and tree; it changes only whether the advertised
|
|
532
|
-
source ref is fetched with depth one or with its reachable history.
|
|
533
|
-
|
|
534
|
-
The cache can be a local/LAN mirror URL template or a runner-local bare
|
|
535
|
-
reference repository template. Templates support `{owner}`, `{repo}`,
|
|
536
|
-
`{repository}`, `{repositorySlug}`, and `{sha}`. The workflow also reads
|
|
537
|
-
repository or organization variables named
|
|
538
|
-
`BUILDCHAIN_CHECKOUT_CACHE_MIRROR_URL_TEMPLATE` and
|
|
539
|
-
`BUILDCHAIN_CHECKOUT_CACHE_REFERENCE_REPOSITORY_TEMPLATE`, so consumers can keep
|
|
540
|
-
private LAN topology out of repository YAML.
|
|
541
|
-
|
|
542
|
-
The GitHub-hosted trust gate resolves the reusable workflow shell to an exact
|
|
543
|
-
commit and uploads that shell's small checkout bootstrap script. Native and
|
|
544
|
-
Linux-container build jobs download the bootstrap, then use the same cache
|
|
545
|
-
policy to obtain both the selected Buildchain runtime and consumer source at
|
|
546
|
-
their already resolved immutable SHAs. Keeping the bootstrap owned by the
|
|
547
|
-
workflow shell is important when `@vN-alpha` routes a stable release to an older
|
|
548
|
-
`vN` runtime: the stable runtime does not need to already contain the newest
|
|
549
|
-
checkout transport implementation. This also prevents a large direct
|
|
550
|
-
`actions/checkout` runtime clone from becoming a separate timeout path on
|
|
551
|
-
constrained self-hosted uplinks. The bootstrap artifact does not contain the
|
|
552
|
-
runtime repository and cannot move either selected ref.
|
|
553
|
-
|
|
554
|
-
Do not read cache URLs or reference paths from PR-controlled files such as
|
|
555
|
-
`.buildchain/buildchain.toml`. These values are trusted workflow inputs or repo/org
|
|
556
|
-
variables. Buildchain does not pass GitHub credentials to cache mirrors or
|
|
557
|
-
reference repositories. If it must fall back to GitHub, the workflow token is
|
|
558
|
-
used only for the GitHub fetch path. Cache attempts use
|
|
559
|
-
`checkout-cache-timeout-seconds`; the potentially larger GitHub fallback uses
|
|
560
|
-
the independent `checkout-cache-github-timeout-seconds` budget (600 seconds by
|
|
561
|
-
default). Buildchain fetches the advertised source ref before trying an exact
|
|
562
|
-
SHA, so a cache hit or stale-cache seed can contribute objects and the fallback
|
|
563
|
-
does not first waste a full timeout on an unadvertised SHA. Retryable timeout
|
|
564
|
-
and transient network failures use the bounded `checkout-cache-fetch-attempts`
|
|
565
|
-
budget; permanent failures stop immediately. Diagnostics record both timeout
|
|
566
|
-
budgets and the actual GitHub fetch attempts before exact HEAD/tree
|
|
567
|
-
verification.
|
|
568
|
-
|
|
569
|
-
Each platform diagnostics artifact includes `source-checkout.json` and embeds a
|
|
570
|
-
compact `sourceCheckout` summary in `diagnostics.json`: mode, transport,
|
|
571
|
-
hit/miss, fallback reason, duration, final HEAD verification, and tree
|
|
572
|
-
verification. Remote URLs are sanitized and local reference paths are represented
|
|
573
|
-
by a short display name plus fingerprint, not by secret-bearing credentials.
|
|
574
|
-
Runtime checkout evidence is uploaded separately as `runtime-checkout.json`,
|
|
575
|
-
including cache transport, fallback attempts, and exact runtime `HEAD`
|
|
576
|
-
verification, even when a later lifecycle step fails.
|
|
577
|
-
|
|
578
|
-
## Auditable Compiler Cache
|
|
579
|
-
|
|
580
|
-
Consumers can prepare `sccache` on selected platforms after the install
|
|
581
|
-
lifecycle and before compilation:
|
|
582
|
-
|
|
583
|
-
```yaml
|
|
584
|
-
with:
|
|
585
|
-
compiler-cache-provider: sccache
|
|
586
|
-
compiler-cache-platforms-json: '["windows-x64"]'
|
|
587
|
-
compiler-cache-required: true
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
The consumer remains responsible for installing and pinning the tool before
|
|
591
|
-
the preparation step. Buildchain probes its version, runs `sccache
|
|
592
|
-
--zero-stats`, and writes
|
|
593
|
-
`compiler-cache-preparation.json`. The receipt binds the source commit/tree,
|
|
594
|
-
Buildchain runtime, platform, cache profile, and any declared dependency,
|
|
595
|
-
toolchain, or policy roots. It resets counters only; it does not delete cached
|
|
596
|
-
compiler outputs. The same preparation exports `RUSTC_WRAPPER`,
|
|
597
|
-
`CMAKE_C_COMPILER_LAUNCHER`, and `CMAKE_CXX_COMPILER_LAUNCHER` so Cargo and
|
|
598
|
-
CMake/Ninja compilation actually passes through the audited tool.
|
|
599
|
-
|
|
600
|
-
After the build lifecycle, Buildchain probes the reset counter set again. When
|
|
601
|
-
`compiler-cache-required` is true, the build fails closed if sccache observed
|
|
602
|
-
zero compiler requests or zero cacheable requests. This prevents an installed
|
|
603
|
-
but unbound sccache binary from being reported as an active compiler cache.
|
|
604
|
-
|
|
605
|
-
Final diagnostics admit sccache hit/miss outcomes as current-run evidence only
|
|
606
|
-
when that preparation receipt is present and valid. A bare `sccache
|
|
607
|
-
--show-stats` result without the reset receipt remains cumulative and is
|
|
608
|
-
reported as unavailable for the current run. The preparation receipt is copied
|
|
609
|
-
into the small diagnostics artifact and sealed by
|
|
610
|
-
`diagnostics-manifest.json`.
|
|
611
|
-
|
|
612
|
-
When a Buildchain maintainer asks for downstream validation, the expected
|
|
613
|
-
request is:
|
|
614
|
-
|
|
615
|
-
```text
|
|
616
|
-
Buildchain train ready: buildchain-ref=train/v3/v3.0/<capability>.
|
|
617
|
-
Keep uses: ...@v3; run workflow_dispatch with that buildchain-ref and report the runtime evidence summary.
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
After validation succeeds, the Buildchain change should continue through the
|
|
621
|
-
normal mainline and release path. Do not treat the train as a pending merge
|
|
622
|
-
item; it is only a temporary fast-use, diagnostic, and rollback channel. It may
|
|
623
|
-
remain for a retention window after release, with old trains handled by a
|
|
624
|
-
separate periodic cleanup task.
|
|
625
|
-
|
|
626
|
-
## Workflow Outputs
|
|
627
|
-
|
|
628
|
-
The reusable workflow exposes the resolved contract:
|
|
629
|
-
|
|
630
|
-
| Output | Meaning |
|
|
631
|
-
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
632
|
-
| `runner-preset` | Resolved preset, or `custom` when `platforms-json` was provided |
|
|
633
|
-
| `platforms-json` | Exact matrix JSON used by the build job |
|
|
634
|
-
| `platform-count` | Number of matrix platforms |
|
|
635
|
-
| `linux-container-enabled` | `true` when Linux platforms are routed through a job container |
|
|
636
|
-
| `linux-container-image` | Resolved digest-pinned Linux job container image |
|
|
637
|
-
| `build-summary-artifact` | Uploaded aggregate summary artifact name |
|
|
638
|
-
| `build-diagnostics-summary-artifact` | Uploaded aggregate diagnostics summary artifact name |
|
|
639
|
-
| `release-candidate-passport-artifact` | Uploaded PR-stage release-candidate passport artifact name when `release-candidate` is enabled |
|
|
640
|
-
| `release-candidate-passport-json` | Compact release-candidate passport JSON when `release-candidate` is enabled |
|
|
641
|
-
| `build-summary-json` | Compact aggregate JSON with platform count, file count, and byte total |
|
|
642
|
-
| `build-diagnostics-summary-json` | Compact aggregate diagnostics JSON with platform, lifecycle warning/error, diagnostics contract warning, and sidecar manifest warning totals |
|
|
643
|
-
| `trusted-event` | `true` when the event is trusted enough to reach build runners |
|
|
644
|
-
| `buildchain-runtime-ref` | Runtime ref selected after applying the empty-default or override policy |
|
|
645
|
-
| `buildchain-runtime-sha` | Immutable Buildchain runtime commit used by all runtime checkouts |
|
|
646
|
-
| `buildchain-runtime-class` | `stable`, `alpha`, `authority`, `train`, `exact-sha`, or `development` |
|
|
647
|
-
| `buildchain-runtime-override` | `true` when an authority, train, or exact-SHA `buildchain-ref` override was accepted |
|
|
648
|
-
| `buildchain-runtime-trust-decision` | Runtime override trust decision |
|
|
649
|
-
| `buildchain-contract-lock-status` | `unchanged`, `compatible-drift`, `breaking-drift`, `missing-lock`, `non-floating-runtime`, or first-release `runtime-contract-unavailable` |
|
|
650
|
-
| `buildchain-contract-lock-drift` | `true` when the floating runtime SHA or contract digest changed |
|
|
651
|
-
| `buildchain-contract-digest` | Current Buildchain runtime contract digest |
|
|
652
|
-
| `publish-channel` | Resolved publish channel requested by the caller |
|
|
653
|
-
| `publish-allowed` | `true` only when this event/ref may publish after verification |
|
|
654
|
-
| `publish-reason` | Human-readable reason for the publish gate decision |
|
|
655
|
-
| `publish-source-ref` | Gate source ref that was resolved before checkout |
|
|
656
|
-
| `publish-source-sha` | Exact source commit used by checkout, build, verify, and artifacts |
|
|
657
|
-
| `publish-source-locked` | `true` when a `publish-gate/*` source ref was explicitly locked |
|
|
658
|
-
| `publish-source-channel` | `alpha`, `release`, `anchor`, or `major` parsed from the source ref |
|
|
659
|
-
| `publish-source-line` | Product line parsed from source refs such as `v22/v22.22` |
|
|
660
|
-
| `publish-source-consumer-version` | Consumer package version parsed from source refs |
|
|
661
|
-
| `release-manifest-json` | Resolved release manifest including source lock, version state, and anchor data |
|
|
662
|
-
|
|
663
|
-
The aggregate summaries are intentionally artifacts as well as outputs. GitHub
|
|
664
|
-
Actions matrix outputs are not a reliable place to carry every platform's full
|
|
665
|
-
manifest, so Buildchain uploads each platform manifest and then emits one
|
|
666
|
-
aggregate build summary artifact after the matrix completes. Buildchain uploads
|
|
667
|
-
`diagnostics-summary.json` as a separate aggregate diagnostics summary artifact,
|
|
668
|
-
a compact rollup of each platform's small diagnostics upload. The rollup keeps
|
|
669
|
-
per-platform runner facts, checked tool versions/missing tools, package
|
|
670
|
-
manager/cache directory details, compiler-cache availability, lifecycle timing,
|
|
671
|
-
process sampler context, and links back to the exact platform artifacts. Each
|
|
672
|
-
platform diagnostics upload includes `diagnostics.json`,
|
|
673
|
-
`diagnostics-manifest.json`, the lifecycle `events.jsonl`, and process sampler
|
|
674
|
-
sidecars when enabled, so slow-build diagnosis does not require downloading the
|
|
675
|
-
binary platform artifact or the aggregate build summary. The sidecar manifest
|
|
676
|
-
records the uploaded diagnostics files with bytes and sha256 hashes. Each
|
|
677
|
-
`diagnostics.json` also records the related binary artifact name, manifest
|
|
678
|
-
artifact name, diagnostics artifact name, diagnostics sidecar manifest path, and
|
|
679
|
-
platform id in `links`, so a reviewer can navigate from the small diagnostics
|
|
680
|
-
artifact back to the exact platform outputs when deeper inspection is needed.
|
|
681
|
-
The workflow output `build-diagnostics-summary-json` includes
|
|
682
|
-
`diagnosticsContractWarningCount` and `diagnosticsManifestWarningCount` so
|
|
683
|
-
release jobs can detect drifting diagnostics JSON contracts and missing or
|
|
684
|
-
drifting diagnostics sidecar manifests without downloading the per-platform
|
|
685
|
-
diagnostics artifacts first.
|
|
686
|
-
|
|
687
|
-
## Artifact Signing Authority
|
|
688
|
-
|
|
689
|
-
Artifact signing is a Buildchain capability, not a macOS application workflow.
|
|
690
|
-
Consumers declare desired signature state next to their artifact facts; they do
|
|
691
|
-
not configure certificates, Team IDs, notary credentials, protected
|
|
692
|
-
environments, authority roles, or signing jobs:
|
|
61
|
+
## Project configuration
|
|
693
62
|
|
|
694
63
|
```toml
|
|
695
|
-
|
|
696
|
-
id = "native-engine"
|
|
697
|
-
path = "dist/kungfu-engine"
|
|
698
|
-
profile = "auto"
|
|
699
|
-
kind = "mach-o"
|
|
700
|
-
platforms = ["macos-arm64", "macos-x64"]
|
|
701
|
-
```
|
|
64
|
+
schema = 1
|
|
702
65
|
|
|
703
|
-
Every native and container build lane reads this declaration after the build
|
|
704
|
-
lifecycle and before verification. Buildchain binds the exact artifact bytes or directory tree to
|
|
705
|
-
the caller repository, source commit, source tree, immutable runtime, platform,
|
|
706
|
-
and requested signature semantics, then publishes a deterministic
|
|
707
|
-
`<artifact>-signing-request-<platform>-<source-sha>-<run-id>-<run-attempt>`
|
|
708
|
-
request. No consumer
|
|
709
|
-
workflow step is required. The lifecycle runner automatically adds declarations
|
|
710
|
-
selected for the current platform to the `build` manifest scan, including
|
|
711
|
-
subjects outside the caller's ordinary `artifact-paths`; this extends the
|
|
712
|
-
evidence preimage without silently adding those subjects to the ordinary
|
|
713
|
-
artifact upload.
|
|
714
|
-
|
|
715
|
-
The request root is a Buildchain-owned generated output. After the declaration,
|
|
716
|
-
lifecycle manifest, and source paths pass validation, sealing replaces that root
|
|
717
|
-
before materializing the current request set. This keeps repeated jobs on a
|
|
718
|
-
self-hosted runner idempotent and prevents stale requests from an earlier run
|
|
719
|
-
from entering the uploaded request artifact. An output root that contains the
|
|
720
|
-
workspace, working directory, lifecycle manifest, or any declared subject is
|
|
721
|
-
rejected before cleanup.
|
|
722
|
-
|
|
723
|
-
Self-hosted runners whose network requires different routes for Artifact upload
|
|
724
|
-
and download can scope an upload-only proxy bypass to the sealed signing request:
|
|
725
|
-
|
|
726
|
-
```yaml
|
|
727
|
-
with:
|
|
728
|
-
artifact-signing-request-upload-no-proxy: ".blob.core.windows.net"
|
|
729
|
-
```
|
|
730
|
-
|
|
731
|
-
The caller repository variable
|
|
732
|
-
`BUILDCHAIN_ARTIFACT_SIGNING_REQUEST_UPLOAD_NO_PROXY` provides the same value
|
|
733
|
-
without changing a consumer workflow; an explicit workflow input takes
|
|
734
|
-
precedence. When neither is set, Buildchain preserves the runner's existing
|
|
735
|
-
`NO_PROXY` and `no_proxy` values. The resolved value applies only to the
|
|
736
|
-
Buildchain-owned signing-request upload. Authority dispatch and immutable
|
|
737
|
-
signed-result download keep the runner's original proxy route. This is a
|
|
738
|
-
transport control only: it does not change request bytes, signing authority,
|
|
739
|
-
artifact identity, or verification policy.
|
|
740
|
-
|
|
741
|
-
`profile = "auto"` resolves signable Apple artifacts such as Mach-O files,
|
|
742
|
-
`.dylib`, `.framework`, `.app`, `.xpc`, `.plugin`, `.pkg`, `.dmg`, and macOS
|
|
743
|
-
archives containing native code to the native `apple-developer-id` provider.
|
|
744
|
-
For a declared macOS `archive`, the authority safely extracts the sealed
|
|
745
|
-
container, signs and verifies every Mach-O payload, signs Mach-O payloads inside
|
|
746
|
-
embedded Python wheels, rebuilds each affected wheel's PEP 427 `RECORD`, and
|
|
747
|
-
recreates the original zip or tar.gz before returning the exact final bytes.
|
|
748
|
-
Archives whose executable hosts a JIT runtime can additionally request the
|
|
749
|
-
Buildchain-owned `entitlements_profile = "jit-executable-v1"` and exact paths,
|
|
750
|
-
for example `entitlements_paths = ["product/runtime/python/bin/python3"]`.
|
|
751
|
-
Paths are relative to the extracted archive root. The authority
|
|
752
|
-
then attaches only `com.apple.security.cs.allow-jit` to the exact executable
|
|
753
|
-
Mach-O files sealed in `entitlements_paths`, leaves every other executable and
|
|
754
|
-
library without exception entitlements, and records the profile, paths, and
|
|
755
|
-
entitled executable count in provider evidence. Consumer-provided entitlement
|
|
756
|
-
files and wildcard target paths are unsupported. The profile is valid only for
|
|
757
|
-
Apple `archive` requests and fails closed on an unsafe, missing,
|
|
758
|
-
non-executable, duplicate, or unsealed target path.
|
|
759
|
-
Windows `pe` and `binary` artifacts
|
|
760
|
-
resolve to timestamped native `windows-authenticode`; Windows PE never falls
|
|
761
|
-
back to a detached signature. Linux and other non-native binary files,
|
|
762
|
-
archives, blobs, and directories resolve to `detached-signature-v1`. Buildchain records that as a
|
|
763
|
-
detached cryptographic signature and never misrepresents it as an operating
|
|
764
|
-
system code signature. Explicit incompatible provider/kind/platform
|
|
765
|
-
combinations fail closed.
|
|
766
|
-
|
|
767
|
-
The request schema rejects credential and authority-infrastructure fields. The
|
|
768
|
-
Buildchain-owned signing authority is responsible for credential selection,
|
|
769
|
-
native signing, notarization where applicable, immutable result delivery, and a
|
|
770
|
-
receipt bound to the request digest, runtime SHA, output digest, and signature
|
|
771
|
-
evidence. Consumer repositories neither receive nor duplicate credential-island
|
|
772
|
-
material. Each platform lane seals and uploads the unsigned request plus a
|
|
773
|
-
run-attempt-bound control request, completes functional verification, and exits.
|
|
774
|
-
It does not dispatch or poll the authority. A separate `ubuntu-24.04` controller
|
|
775
|
-
starts only after the build matrices complete, validates the exact source,
|
|
776
|
-
tree, runtime, request-set root, platform, run attempt, and correlation, then
|
|
777
|
-
dispatches and awaits the protected authority workflow. Its retained receipt
|
|
778
|
-
records two independent immutable identities: the consumer Buildchain runtime
|
|
779
|
-
SHA carried by the control request and the exact authority-ref commit resolved
|
|
780
|
-
immediately before dispatch. The former validates the request-producing
|
|
781
|
-
runtime; the latter must equal the authority workflow run's `head_sha` and is
|
|
782
|
-
retained with the exact authority run and result artifact. If the protected ref
|
|
783
|
-
moves between resolution and dispatch, settlement fails closed. Failure, timeout, or
|
|
784
|
-
cancellation produces a non-qualifying receipt and no finalization delegation.
|
|
785
|
-
|
|
786
|
-
A second GitHub-hosted finalization lane downloads the original control request,
|
|
787
|
-
controller receipt, and delegation, verifies their roots and coordinates agree,
|
|
788
|
-
then verifies the authority result against the sealed request, imports the exact
|
|
789
|
-
signed bytes, and recomputes the final manifest before replacing the
|
|
790
|
-
deterministic artifact. The signing result is never downloaded back to a
|
|
791
|
-
self-hosted native runner, so a macOS caller is released before credential-island
|
|
792
|
-
signing and notarization complete.
|
|
793
|
-
Platform manifests, KFD evidence, checksums, and Release Passport inputs
|
|
794
|
-
therefore observe the final signed artifact rather than the pre-signing build
|
|
795
|
-
output.
|
|
796
|
-
|
|
797
|
-
For a standalone Mach-O request, the authority requires strict Developer ID
|
|
798
|
-
verification, the declared Team ID, hardened runtime, and an `Accepted`
|
|
799
|
-
`notarytool` result for the exact submission. Apple creates the notarization
|
|
800
|
-
ticket for that binary and publishes it online, but
|
|
801
|
-
[standalone binaries do not support stapling](https://developer.apple.com/documentation/security/customizing-the-notarization-workflow).
|
|
802
|
-
Buildchain therefore records
|
|
803
|
-
`standalone-notary-ticket-online` and does not misapply app-bundle
|
|
804
|
-
`spctl --assess --type execute` semantics to the raw executable.
|
|
805
|
-
|
|
806
|
-
For a compound archive request, the authority notarizes the complete extracted
|
|
807
|
-
signed product tree and records `compound-notary-ticket-online`. A generic
|
|
808
|
-
archive container cannot carry a stapled ticket and is not itself a Gatekeeper
|
|
809
|
-
execution target; Gatekeeper evaluates the extracted signed code. Archive path
|
|
810
|
-
and symlink validation fail closed before any payload is signed.
|
|
811
|
-
|
|
812
|
-
For a declared `app-bundle`, the same protected authority extracts the sealed
|
|
813
|
-
application, derives and verifies its bundle identity, signs nested native code,
|
|
814
|
-
submits both the application and disk image for notarization, staples and
|
|
815
|
-
Gatekeeper-assesses both deliverables, and returns a ZIP, DMG, evidence document,
|
|
816
|
-
and source-bound manifest. The reusable workflow verifies those returned bytes
|
|
817
|
-
on GitHub-hosted infrastructure, adds them to the normal macOS platform payload,
|
|
818
|
-
and publishes a separate `<artifact>-macos-credential-<source-sha>` projection
|
|
819
|
-
for release pipelines that consume the credential-island evidence contract.
|
|
820
|
-
Consumers declare the `.app` under `[[signing.artifacts]]`; they do not configure
|
|
821
|
-
an environment, certificate, notary credential, or authority workflow.
|
|
822
|
-
|
|
823
|
-
The durable v3 authority runtime is
|
|
824
|
-
`authority/v3/v3.0/artifact-signing`. It is channel-neutral: alpha and stable
|
|
825
|
-
release work use the same protected `buildchain-artifact-signing` environment
|
|
826
|
-
and provider identities. The authority ref is protected independently from
|
|
827
|
-
release channels and can advance only through reviewed, checked changes; the
|
|
828
|
-
temporary `train/v3/v3.0/artifact-signing-authority` ref is retained only as a
|
|
829
|
-
bounded migration rollback.
|
|
830
|
-
|
|
831
|
-
The older `credential-island-macos-*` reusable-workflow inputs remain a
|
|
832
|
-
compatibility surface while existing callers migrate. They are not the target
|
|
833
|
-
consumer contract and must not be used to design new integrations.
|
|
834
|
-
|
|
835
|
-
## Artifact Transfer Relay
|
|
836
|
-
|
|
837
|
-
By default, platform jobs upload payloads, manifests, and diagnostics directly
|
|
838
|
-
to GitHub artifacts:
|
|
839
|
-
|
|
840
|
-
```yaml
|
|
841
|
-
with:
|
|
842
|
-
artifact-transfer-mode: github-artifacts
|
|
843
|
-
artifact-compression-level: 0
|
|
844
|
-
```
|
|
845
|
-
|
|
846
|
-
Direct GitHub Artifact payloads default to compression level `0`. Buildchain
|
|
847
|
-
artifacts are commonly already-compressed archives; storing them without a
|
|
848
|
-
second compression pass shortens the upload window while preserving the same
|
|
849
|
-
artifact name, run/id/digest binding, retention, and no-overwrite behavior.
|
|
850
|
-
Direct build and signed-finalization payload uploads include hidden files under
|
|
851
|
-
the caller-declared artifact paths, matching the relay path so manifest-bound
|
|
852
|
-
dotfiles are not silently removed in transit.
|
|
853
|
-
Callers may select `1` through `9` for payloads that materially benefit from
|
|
854
|
-
compression. Manifests and diagnostics retain their existing small-artifact
|
|
855
|
-
behavior.
|
|
856
|
-
|
|
857
|
-
Large self-hosted native builds can opt into the first-class S3 relay path:
|
|
858
|
-
|
|
859
|
-
```yaml
|
|
860
|
-
jobs:
|
|
861
|
-
build:
|
|
862
|
-
uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
|
|
863
|
-
with:
|
|
864
|
-
runner-preset: kungfu-v4-self-hosted
|
|
865
|
-
artifact-transfer-mode: s3-to-github-artifacts
|
|
866
|
-
artifact-relay-s3-bucket: ${{ vars.BUILDCHAIN_ARTIFACT_RELAY_S3_BUCKET }}
|
|
867
|
-
artifact-relay-s3-region: ${{ vars.BUILDCHAIN_ARTIFACT_RELAY_S3_REGION }}
|
|
868
|
-
artifact-relay-s3-prefix: ${{ vars.BUILDCHAIN_ARTIFACT_RELAY_S3_PREFIX }}
|
|
869
|
-
```
|
|
870
|
-
|
|
871
|
-
The mode is a policy for platforms that run outside GitHub. GitHub-hosted
|
|
872
|
-
platforms always upload directly with `actions/upload-artifact`, even when a
|
|
873
|
-
mixed matrix requests `s3-to-github-artifacts`; they never send their payloads
|
|
874
|
-
through S3 or the replay job. Buildchain recognizes its hosted presets and the
|
|
875
|
-
standard hosted runner labels. Custom matrices with non-standard hosted labels
|
|
876
|
-
must declare `"githubHosted": true` on those platform rows.
|
|
877
|
-
|
|
878
|
-
For remaining relay-mode platforms, each job uploads the heavy payload files to
|
|
879
|
-
S3 and uploads only a small `relay-manifest.json` to GitHub. A GitHub-hosted
|
|
880
|
-
`relay-artifacts` job then assumes the configured download role, downloads the
|
|
881
|
-
payloads from S3, verifies every file by SHA256, and re-uploads the normal
|
|
882
|
-
GitHub artifacts under the same artifact names that direct mode uses. Downstream
|
|
883
|
-
summary, release-candidate, and promote-only workflows therefore continue to
|
|
884
|
-
consume GitHub artifacts and do not need custom S3 logic.
|
|
885
|
-
The relay implementation uses Node.js plus the standard AWS environment
|
|
886
|
-
credentials from GitHub OIDC; runner images and build containers do not need the
|
|
887
|
-
AWS CLI installed.
|
|
888
|
-
|
|
889
|
-
After the GitHub artifact uploads succeed, Buildchain deletes the S3 objects
|
|
890
|
-
listed in the relay manifest for that platform. If any download, verification,
|
|
891
|
-
or GitHub artifact upload fails, cleanup is skipped so maintainers can inspect
|
|
892
|
-
the retained S3 payload. Configure a short bucket lifecycle expiration as a
|
|
893
|
-
cost and cleanup backstop.
|
|
894
|
-
|
|
895
|
-
The relay configuration is intentionally generic. Buildchain does not hard-code
|
|
896
|
-
organization buckets, regions, or role ARNs. Callers may pass explicit inputs,
|
|
897
|
-
or set repository/organization variables and secrets using these names:
|
|
898
|
-
|
|
899
|
-
| Variable or secret | Meaning |
|
|
900
|
-
| ------------------------------------------------ | ------------------------------------------------------- |
|
|
901
|
-
| `BUILDCHAIN_ARTIFACT_RELAY_S3_BUCKET` | Relay bucket name |
|
|
902
|
-
| `BUILDCHAIN_ARTIFACT_RELAY_S3_REGION` | Relay bucket region |
|
|
903
|
-
| `BUILDCHAIN_ARTIFACT_RELAY_S3_PREFIX` | Relay object prefix; defaults to `buildchain-artifacts` |
|
|
904
|
-
| `BUILDCHAIN_ARTIFACT_RELAY_S3_ROLE_ARN` | Shared OIDC role ARN for upload and download |
|
|
905
|
-
| `BUILDCHAIN_ARTIFACT_RELAY_S3_UPLOAD_ROLE_ARN` | Upload OIDC role ARN for self-hosted build jobs |
|
|
906
|
-
| `BUILDCHAIN_ARTIFACT_RELAY_S3_DOWNLOAD_ROLE_ARN` | Download OIDC role ARN for the GitHub-hosted relay job |
|
|
907
|
-
| `BUILDCHAIN_ARTIFACT_RELAY_S3_OIDC_AUDIENCE` | Optional OIDC audience override |
|
|
908
|
-
|
|
909
|
-
For AWS China regions, Buildchain defaults the OIDC audience to
|
|
910
|
-
`sts.amazonaws.com.cn`; other regions default to `sts.amazonaws.com`. The caller
|
|
911
|
-
workflow must allow `id-token: write`, and the target role trust policy should
|
|
912
|
-
restrict GitHub OIDC claims to the expected organization, repository, workflow,
|
|
913
|
-
and branch/ref. The S3 permissions should be scoped to the relay bucket/prefix
|
|
914
|
-
used by the repository.
|
|
915
|
-
Upload roles need write/delete access under the relay prefix; download roles
|
|
916
|
-
need read access plus delete access for successful cleanup.
|
|
917
|
-
|
|
918
|
-
Relay mode is opt-in and does not affect forks or open-source users that do not
|
|
919
|
-
configure S3. Missing bucket, region, upload role, or download role values fail
|
|
920
|
-
before the heavy build matrix is scheduled. Buildchain treats S3 as a transport
|
|
921
|
-
cache, not as the final release evidence store; the final audit entry remains
|
|
922
|
-
the GitHub artifact set plus the Buildchain build summary and release-candidate
|
|
923
|
-
passport.
|
|
924
|
-
|
|
925
|
-
Set `release-candidate: true` when the successful reusable build is meant to be
|
|
926
|
-
the artifact source promoted later. Buildchain then uploads
|
|
927
|
-
`release-candidate-passport.json` under the
|
|
928
|
-
`<artifact-name>-release-candidate-<publish-source-sha>` artifact name. Promotion
|
|
929
|
-
jobs can pass that passport to `promote-buildchain-ref` with
|
|
930
|
-
`promote-only-release-candidate: "true"` so source, channel, platforms, and the
|
|
931
|
-
aggregate build-summary hash are checked before publish-gate side effects. The
|
|
932
|
-
passport records the locked commit's Git tree SHA, so a post-merge channel HEAD
|
|
933
|
-
can be accepted only when it is tree-equivalent to the PR-stage build evidence.
|
|
934
|
-
|
|
935
|
-
## Publish Gate
|
|
936
|
-
|
|
937
|
-
Buildchain separates "may build/verify" from "may publish." A same-repository
|
|
938
|
-
pull request may be trusted enough to run the build matrix, but it still must
|
|
939
|
-
not publish packages, S3 objects, release pages, or preview aliases. Publishing
|
|
940
|
-
is allowed only when the caller explicitly requests a channel and the current
|
|
941
|
-
event/ref matches that channel.
|
|
942
|
-
|
|
943
|
-
Use `publish-channel` to request a channel:
|
|
944
|
-
|
|
945
|
-
```yaml
|
|
946
|
-
jobs:
|
|
947
|
-
build:
|
|
948
|
-
uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
|
|
949
|
-
with:
|
|
950
|
-
publish-channel: release
|
|
951
|
-
|
|
952
|
-
publish:
|
|
953
|
-
needs: build
|
|
954
|
-
if: ${{ needs.build.outputs.publish-allowed == 'true' }}
|
|
955
|
-
runs-on: ubuntu-24.04
|
|
956
|
-
steps:
|
|
957
|
-
- run: ./scripts/publish.sh
|
|
958
|
-
```
|
|
959
|
-
|
|
960
|
-
Default channels are:
|
|
961
|
-
|
|
962
|
-
| Channel | Allowed refs |
|
|
963
|
-
| --------- | ---------------------------------------------------------------------------------------------------- |
|
|
964
|
-
| `none` | Never publishes; this is the default |
|
|
965
|
-
| `alpha` | `alpha/vN/vN.M` branches or exact `vN.M.P-alpha.K` tags |
|
|
966
|
-
| `release` | `release/vN/vN.M` branches or release tags such as `vN.M.P`, `vN.M`, `vN` |
|
|
967
|
-
| `major` | `publish-gate/major`, legacy `major-gate`, or next-major release tags such as `vN.0.0`, `vN.0`, `vN` |
|
|
968
|
-
|
|
969
|
-
Pull request events always produce `publish-allowed=false`, even when the PR is
|
|
970
|
-
from the same repository. Untrusted fork events also produce
|
|
971
|
-
`publish-allowed=false`; with the default `untrusted-policy: fail`, the workflow
|
|
972
|
-
then fails before any build runner starts.
|
|
973
|
-
|
|
974
|
-
Projects with their own channel names can pass `publish-refs-json`:
|
|
975
|
-
|
|
976
|
-
```yaml
|
|
977
|
-
with:
|
|
978
|
-
publish-channel: nightly
|
|
979
|
-
publish-refs-json: >-
|
|
980
|
-
{"nightly":["^refs/heads/nightly/v\\d+$"]}
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
The aggregate build summary includes the same publish gate decision under
|
|
984
|
-
`publishGate`, so a downloaded artifact summary explains both what was built and
|
|
985
|
-
why it was or was not eligible to publish.
|
|
986
|
-
|
|
987
|
-
## Publish Source Lock
|
|
988
|
-
|
|
989
|
-
`publish-channel` answers "may this event publish?" Source lock answers "which
|
|
990
|
-
source tree is the publish decision about?" A caller can pass `publish-source-ref`
|
|
991
|
-
to bind a publish run to a reviewed gate branch before any checkout happens:
|
|
992
|
-
|
|
993
|
-
| Ref | Meaning |
|
|
994
|
-
| ------------------------------------------------ | --------------------------------------------------------------------------- |
|
|
995
|
-
| `publish-gate/alpha/<line>/<consumer-version>` | Build and publish an alpha candidate for a consumer line |
|
|
996
|
-
| `publish-gate/release/<line>/<consumer-version>` | Build and publish a production candidate for a consumer line |
|
|
997
|
-
| `publish-gate/anchor` | Resolve an explicit anchor request; it does not publish artifacts by itself |
|
|
998
|
-
| `publish-gate/major` | Gate the next major source state |
|
|
999
|
-
| `major-gate` | Legacy compatibility alias for the major gate |
|
|
1000
|
-
|
|
1001
|
-
For alpha and release refs, `<line>` is intentionally allowed to contain `/`, so
|
|
1002
|
-
Kungfu-style lines such as `v22/v22.22` stay readable. The final path segment is
|
|
1003
|
-
the consumer-visible version, for example `22.22.3-kf.0`.
|
|
1004
|
-
|
|
1005
|
-
The reusable workflow resolves the branch tip to `publish-source-sha`, checks out
|
|
1006
|
-
that SHA in every build job, and uses the same SHA in artifact names, manifests,
|
|
1007
|
-
and aggregate summaries. Reruns therefore rebuild the same source tree even if a
|
|
1008
|
-
gate branch moves later.
|
|
1009
|
-
|
|
1010
|
-
Before any heavy build matrix is scheduled, the workflow also verifies that the
|
|
1011
|
-
target channel ref implied by the source lock already points at
|
|
1012
|
-
`publish-source-sha` and that the target channel HEAD came from the required
|
|
1013
|
-
merged same-repository channel PR. `publish-gate/alpha/<line>/<version>` must
|
|
1014
|
-
match `alpha/<line>` and have PR lineage `dev/<line> -> alpha/<line>`;
|
|
1015
|
-
`publish-gate/release/<line>/<version>` must match `release/<line>` and have PR
|
|
1016
|
-
lineage `alpha/<line> -> release/<line>`. If either check fails, the run fails
|
|
1017
|
-
fast with a diagnostic telling maintainers to merge the source commit through
|
|
1018
|
-
the channel PR first. This keeps verify from spending runner time on a source
|
|
1019
|
-
tree that cannot legally enter the requested publish channel.
|
|
1020
|
-
|
|
1021
|
-
The resolved release manifest is uploaded as an artifact and emitted as
|
|
1022
|
-
`release-manifest-json`. It records:
|
|
1023
|
-
|
|
1024
|
-
- source ref, source SHA, channel, line, and consumer version;
|
|
1025
|
-
- configured version strategy and configured version-state files;
|
|
1026
|
-
- each version file's value, with release gates failing closed if the configured
|
|
1027
|
-
files do not equal the consumer version;
|
|
1028
|
-
- anchor manifest summary for anchored/manual projects;
|
|
1029
|
-
- explicit anchor request JSON for `publish-gate/anchor`;
|
|
1030
|
-
- publish registry, dist-tag, and gate visibility metadata.
|
|
1031
|
-
|
|
1032
|
-
Publish side-effect jobs should verify the lock immediately before publishing:
|
|
1033
|
-
|
|
1034
|
-
```yaml
|
|
1035
|
-
- name: Verify publish gate did not move
|
|
1036
|
-
run: node .buildchain/runtime/scripts/verify-publish-source-lock.mjs
|
|
1037
|
-
env:
|
|
1038
|
-
BUILDCHAIN_PUBLISH_SOURCE_REF: ${{ needs.build.outputs.publish-source-ref }}
|
|
1039
|
-
BUILDCHAIN_PUBLISH_SOURCE_SHA: ${{ needs.build.outputs.publish-source-sha }}
|
|
1040
|
-
BUILDCHAIN_SOURCE_REPOSITORY: ${{ github.repository }}
|
|
1041
|
-
GITHUB_TOKEN: ${{ github.token }}
|
|
1042
|
-
```
|
|
1043
|
-
|
|
1044
|
-
If the branch tip no longer matches the manifest SHA, the publish job must fail
|
|
1045
|
-
closed. Moving a gate branch creates a new publish decision and should produce a
|
|
1046
|
-
new build run.
|
|
1047
|
-
|
|
1048
|
-
## Release Candidate Promote-Only
|
|
1049
|
-
|
|
1050
|
-
For native package sets, the PR build is the only heavy build. When a PR targets
|
|
1051
|
-
`alpha/<line>` or `release/<line>`, `.build.yml` uploads a release-candidate
|
|
1052
|
-
bundle next to the platform artifacts. The bundle contains:
|
|
1053
|
-
|
|
1054
|
-
- `release-candidate.passport.json`;
|
|
1055
|
-
- the aggregate `build-summary.json`;
|
|
1056
|
-
- copied platform manifest evidence for the built platforms.
|
|
1057
|
-
|
|
1058
|
-
The passport records two separate source identities:
|
|
1059
|
-
|
|
1060
|
-
- `builtSourceSha` / `builtSourceTreeSha`: the PR-stage source that produced the
|
|
1061
|
-
artifacts, usually the PR merge ref;
|
|
1062
|
-
- `promotionChannelSha` / `promotionChannelTreeSha`: the post-merge channel
|
|
1063
|
-
commit used for publish authority.
|
|
1064
|
-
|
|
1065
|
-
The reusable promote wrapper resolves the merged PR, finds exactly one matching
|
|
1066
|
-
PR-stage release-candidate artifact, downloads it with the build summary and
|
|
1067
|
-
payload artifacts from the same PR-stage run, validates the payload count,
|
|
1068
|
-
compares the built tree with the promotion channel tree, locks
|
|
1069
|
-
`publish-gate/{alpha,release,major}` to the promotion channel commit, and then
|
|
1070
|
-
calls `actions/promote-buildchain-ref` with
|
|
1071
|
-
`promote-only-release-candidate: "true"` and
|
|
1072
|
-
`require-publish-source-lock: "true"`. The wrapper passes the created
|
|
1073
|
-
`publish-gate/*` ref, target SHA, and `locked=true` into the promote action, so
|
|
1074
|
-
floating `@v3` consumers receive publish-side source-lock drift protection by
|
|
1075
|
-
default. It also defaults `branch-protection-bypass-apps` to `github-actions`
|
|
1076
|
-
so the workflow automation can apply generated version-state and channel
|
|
1077
|
-
bookkeeping on protected `dev`/`alpha`/`release` branches after the reviewed
|
|
1078
|
-
channel PR has merged. Other App slugs and all user or team bypass actors are
|
|
1079
|
-
rejected. The wrapper uses the run-scoped `github.token` as the generated ref
|
|
1080
|
-
update token for protected bookkeeping PATCH calls, so the exact GitHub Actions
|
|
1081
|
-
App authority can sync dev immediately after alpha/release publish without a
|
|
1082
|
-
post-publish PR.
|
|
1083
|
-
It does not call `.build.yml`, does not create a matrix, and must fail before
|
|
1084
|
-
publish if the RC evidence, payload set, or source-lock ref is missing or
|
|
1085
|
-
ambiguous.
|
|
1086
|
-
|
|
1087
|
-
The public `release-candidate-promote.yml` is a generated channel router. It
|
|
1088
|
-
derives the publication lane from `target-ref`, then selects the matching
|
|
1089
|
-
advanced workflow shell, runtime, and consumer lock before the advanced
|
|
1090
|
-
promotion starts:
|
|
1091
|
-
|
|
1092
|
-
- alpha targets use `.release-candidate-promote.yml@vN-alpha`, runtime
|
|
1093
|
-
`vN-alpha`, and `buildchain-alpha-contract-lock-path`;
|
|
1094
|
-
- release and major targets use `.release-candidate-promote.yml@vN`, runtime
|
|
1095
|
-
`vN`, and `buildchain-stable-contract-lock-path`.
|
|
1096
|
-
|
|
1097
|
-
The generated router also owns the stable-shell layout transition through
|
|
1098
|
-
`.buildchain/promotion-shell-routing.json`. The v3 stable and alpha lanes call
|
|
1099
|
-
the hidden advanced workflow at the exact immutable SHA behind their selected
|
|
1100
|
-
v3 channel state and forward the complete internal promotion identity surface.
|
|
1101
|
-
The logical shell identity remains `vN`, and the router retains it in the public
|
|
1102
|
-
audit outputs. The internal advanced-shell call receives the exact call ref
|
|
1103
|
-
selected by the routing configuration, so its called-workflow ref check and
|
|
1104
|
-
checkout SHA both bind to the same immutable identity. Updating a routing pin
|
|
1105
|
-
after a release does not require any consumer declaration change.
|
|
1106
|
-
|
|
1107
|
-
The router resolves immutable SHAs and the selected lock digest before candidate
|
|
1108
|
-
download. The advanced shell verifies the same router, shell, runtime, lock,
|
|
1109
|
-
channel, and target binding again. Train and exact-SHA runtime overrides remain
|
|
1110
|
-
restricted to trusted `workflow_dispatch` actors with write, maintain, or admin
|
|
1111
|
-
permission. Promotion controller evidence, the promotion copy of the release
|
|
1112
|
-
candidate passport, and the final release passport record these identities.
|
|
1113
|
-
|
|
1114
|
-
```yaml
|
|
1115
|
-
jobs:
|
|
1116
|
-
promote:
|
|
1117
|
-
uses: kungfu-systems/buildchain/.github/workflows/release-candidate-promote.yml@v3
|
|
1118
|
-
secrets:
|
|
1119
|
-
buildchain-issue-app-id: ${{ secrets.BUILDCHAIN_ISSUE_APP_ID }}
|
|
1120
|
-
buildchain-issue-app-private-key: ${{ secrets.BUILDCHAIN_ISSUE_APP_PRIVATE_KEY }}
|
|
1121
|
-
with:
|
|
1122
|
-
buildchain-channel: auto
|
|
1123
|
-
buildchain-alpha-contract-lock-path: .buildchain/alpha-contract-lock.json
|
|
1124
|
-
buildchain-stable-contract-lock-path: .buildchain/contract-lock.json
|
|
1125
|
-
channel: alpha
|
|
1126
|
-
target-ref: alpha/v22/v22.22
|
|
1127
|
-
artifact-name: libnode
|
|
1128
|
-
# Defaults to build.yml / Build. Override only when the PR-stage build
|
|
1129
|
-
# workflow uses a different file or display name.
|
|
1130
|
-
release-candidate-workflow-file: build.yml
|
|
1131
|
-
release-candidate-workflow-name: Build
|
|
1132
|
-
package-manager: npm
|
|
1133
|
-
publish-target: npm
|
|
1134
|
-
runner-preset: github-hosted
|
|
1135
|
-
trusted-publishing: true
|
|
1136
|
-
github-release: true
|
|
1137
|
-
required-status-check: check / check
|
|
1138
|
-
required-artifact-count: 3
|
|
1139
|
-
publish-dist-tag: alpha
|
|
1140
|
-
publish-package-set-order: platforms-first-main-last
|
|
1141
|
-
publish-package-main: "@kungfu-tech/libnode"
|
|
1142
|
-
release-passport-product-name: Libnode
|
|
1143
|
-
buildchain-contract-drift-issue-mode: compatible-and-breaking
|
|
1144
|
-
```
|
|
1145
|
-
|
|
1146
|
-
Existing callers may keep `buildchain-contract-lock-path`; a non-empty explicit
|
|
1147
|
-
path overrides channel-specific path selection only. Its lock content must
|
|
1148
|
-
still prove the selected channel and major. Migration only requires adding the
|
|
1149
|
-
two channel lock inputs and may retain the remaining common promotion
|
|
1150
|
-
declaration unchanged. Consumers must not call the dot-prefixed advanced
|
|
1151
|
-
workflow directly.
|
|
1152
|
-
|
|
1153
|
-
`buildchain-issue-app-id` and `buildchain-issue-app-private-key` are optional
|
|
1154
|
-
but recommended for cross-repository consumers. They should identify a GitHub
|
|
1155
|
-
App installation with `issues: write` on `kungfu-systems/buildchain`; the
|
|
1156
|
-
wrapper mints the installation token before calling
|
|
1157
|
-
`actions/report-buildchain-issue`. Consumers can also pass a pre-minted
|
|
1158
|
-
`buildchain-issue-token`. If both are omitted, the wrapper falls back to
|
|
1159
|
-
`BUILDCHAIN_ISSUE_TOKEN`, `BUILDCHAIN_PROMOTION_TOKEN`, and then the consumer
|
|
1160
|
-
workflow's `github.token`; the last fallback can only report issues when it has
|
|
1161
|
-
write access to the target Buildchain repository.
|
|
1162
|
-
|
|
1163
|
-
`publish-required-artifacts-json` can still be passed explicitly for custom
|
|
1164
|
-
publish targets. Custom OCI requirements may omit pre-publish refs and digests;
|
|
1165
|
-
the action resolves the exact version ref and validates final digests and any
|
|
1166
|
-
built/reused provenance after `lifecycle.publish`. For the default
|
|
1167
|
-
`publish-artifact-kind: npm` path, consumers do
|
|
1168
|
-
not download artifacts or run repository scripts to build publish evidence. The
|
|
1169
|
-
wrapper downloads the PR-stage payload artifacts, finds the downloaded `.tgz`
|
|
1170
|
-
packages, reads each tarball's `package/package.json` for the real scoped
|
|
1171
|
-
package name and version, computes the npm `sha512-...` integrity from the
|
|
1172
|
-
tarball bytes, marks the package matching `publish-package-main` as `role:
|
|
1173
|
-
main`, marks the rest as `role: platform`, and passes the generated
|
|
1174
|
-
`publish-required-artifacts-json` to `promote-buildchain-ref` before any publish
|
|
1175
|
-
side effect. Downloaded platform manifests are still passed into the release
|
|
1176
|
-
passport unless `release-passport-platform-manifest-paths` is set explicitly.
|
|
1177
|
-
The same Buildchain contract lock check runs before release-candidate
|
|
1178
|
-
resolution and before publish. A compatible `v3` drift leaves an issue in the
|
|
1179
|
-
consumer repository but does not trigger a second heavy build; an incompatible
|
|
1180
|
-
drift fails before publish side effects.
|
|
1181
|
-
|
|
1182
|
-
The wrapper publishes the public release tag as a GitHub Release by default.
|
|
1183
|
-
After `promote-buildchain-ref` reports a complete release transaction, the
|
|
1184
|
-
wrapper creates or updates the public release, marks semver prerelease tags
|
|
1185
|
-
such as `v1.2.3-alpha.0`, `v1.2.3-rc.1`, or `v22.22.3-kf.3-alpha.7` as
|
|
1186
|
-
`prerelease=true` and `make_latest=false`, marks stable semver tags as latest,
|
|
1187
|
-
and uploads the publish evidence file plus every file in the generated release
|
|
1188
|
-
passport directory, including `buildchain.release.json` and `check-report.json`.
|
|
1189
|
-
For anchored/manual package releases, the public release tag is derived from the
|
|
1190
|
-
published package version and the internal exact transaction tag remains
|
|
1191
|
-
available in the release passport.
|
|
1192
|
-
Consumers do not need to hand-write `gh release` logic to trigger
|
|
1193
|
-
`release.published` propagation. Set `github-release: false` only for
|
|
1194
|
-
repositories that intentionally do not maintain GitHub Releases.
|
|
1195
|
-
If the transaction still needs protected-ref finalization, the wrapper defers
|
|
1196
|
-
GitHub Release creation until the later run that reaches `state=complete`.
|
|
1197
|
-
|
|
1198
|
-
Custom publish jobs can also repeat the channel-ref preflight:
|
|
1199
|
-
|
|
1200
|
-
```yaml
|
|
1201
|
-
- name: Verify publish channel ref still matches
|
|
1202
|
-
run: node .buildchain/runtime/scripts/verify-publish-channel-ref.mjs
|
|
1203
|
-
env:
|
|
1204
|
-
BUILDCHAIN_PUBLISH_SOURCE_REF: ${{ needs.build.outputs.publish-source-ref }}
|
|
1205
|
-
BUILDCHAIN_PUBLISH_SOURCE_SHA: ${{ needs.build.outputs.publish-source-sha }}
|
|
1206
|
-
BUILDCHAIN_SOURCE_REPOSITORY: ${{ github.repository }}
|
|
1207
|
-
GITHUB_TOKEN: ${{ github.token }}
|
|
1208
|
-
```
|
|
1209
|
-
|
|
1210
|
-
Anchored/manual package release jobs should also make the Buildchain promotion
|
|
1211
|
-
action validate that publication is entering through the same
|
|
1212
|
-
`publish-gate/{alpha,release,major}` source-lock contract before any package
|
|
1213
|
-
publish side effect:
|
|
1214
|
-
|
|
1215
|
-
```yaml
|
|
1216
|
-
- name: Promote release ref and publish npm package set
|
|
1217
|
-
uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v3
|
|
1218
|
-
with:
|
|
1219
|
-
sha: ${{ needs.build.outputs.publish-source-sha }}
|
|
1220
|
-
target-ref: release/v22/v22.22
|
|
1221
|
-
require-publish-source-lock: "true"
|
|
1222
|
-
publish-source-ref: ${{ needs.build.outputs.publish-source-ref }}
|
|
1223
|
-
publish-source-sha: ${{ needs.build.outputs.publish-source-sha }}
|
|
1224
|
-
publish-source-locked: ${{ needs.build.outputs.publish-source-locked }}
|
|
1225
|
-
```
|
|
1226
|
-
|
|
1227
|
-
`target-ref` stays the Buildchain channel promotion target, such as
|
|
1228
|
-
`alpha/v22/v22.22`, `release/v22/v22.22`, or `publish-gate/major`.
|
|
1229
|
-
`publish-source-ref` is the reviewed source-lock branch that authorized this
|
|
1230
|
-
specific package publication. For alpha and release package publications, the
|
|
1231
|
-
source-lock branch must point at the exact channel-line commit that promotion is
|
|
1232
|
-
validating; it is not a replacement for `target-ref`.
|
|
1233
|
-
|
|
1234
|
-
This keeps the version bump commit, publish authorization, and auditable publish
|
|
1235
|
-
entrypoint on the Buildchain source-lock protocol. The CLI form
|
|
1236
|
-
`buildchain publish-source validate-anchored-release --json` is still useful for
|
|
1237
|
-
custom publish scripts, but the preferred GitHub Actions gate is the promotion
|
|
1238
|
-
action input above. A publish job that still runs directly from `alpha/*` or
|
|
1239
|
-
`release/*` channel branches fails this check because those refs are channel
|
|
1240
|
-
state, not publish-gate decisions.
|
|
1241
|
-
|
|
1242
|
-
## Package-Set Publish Plan
|
|
1243
|
-
|
|
1244
|
-
Projects that publish multiple packages should treat package publication as a
|
|
1245
|
-
package-set operation. Buildchain's package-set planner uses these rules:
|
|
1246
|
-
|
|
1247
|
-
- platform packages publish first;
|
|
1248
|
-
- the main package publishes last;
|
|
1249
|
-
- the dist-tag move happens only after the full package set is present;
|
|
1250
|
-
- reruns accept already-published packages only when package name, version, and
|
|
1251
|
-
integrity match;
|
|
1252
|
-
- an existing package with different integrity is a hard failure.
|
|
1253
|
-
|
|
1254
|
-
This keeps a consumer from observing a floating dist-tag that points to a main
|
|
1255
|
-
package before all platform artifacts for the same source SHA are available.
|
|
1256
|
-
|
|
1257
|
-
## Command Sources
|
|
1258
|
-
|
|
1259
|
-
The workflow runs `.buildchain/buildchain.toml` lifecycle stages by default:
|
|
1260
|
-
|
|
1261
|
-
```toml
|
|
1262
66
|
[lifecycle.install]
|
|
1263
|
-
command = "corepack
|
|
67
|
+
command = "corepack pnpm install --frozen-lockfile"
|
|
1264
68
|
|
|
1265
69
|
[lifecycle.build]
|
|
1266
|
-
|
|
1267
|
-
"corepack yarn make",
|
|
1268
|
-
"corepack yarn build",
|
|
1269
|
-
]
|
|
70
|
+
command = "corepack pnpm build"
|
|
1270
71
|
|
|
1271
72
|
[lifecycle.verify]
|
|
1272
|
-
command = "corepack
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
`
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
`
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
```
|
|
1398
|
-
|
|
1399
|
-
Artifact names do not include actor names, timestamps, or retry counters. Reruns
|
|
1400
|
-
produce a new GitHub Actions run but keep the same source SHA/platform contract.
|
|
1401
|
-
|
|
1402
|
-
`expected-artifacts-json` fails the build before upload when the artifact does
|
|
1403
|
-
not match the caller's declared contract. Supported checks are:
|
|
1404
|
-
|
|
1405
|
-
| Field | Meaning |
|
|
1406
|
-
| --------------- | ------------------------------------ |
|
|
1407
|
-
| `minFiles` | Minimum number of manifest files |
|
|
1408
|
-
| `maxFiles` | Maximum number of manifest files |
|
|
1409
|
-
| `minTotalBytes` | Minimum total byte count |
|
|
1410
|
-
| `requiredPaths` | Exact manifest paths that must exist |
|
|
1411
|
-
|
|
1412
|
-
## Trusted Event Gate
|
|
1413
|
-
|
|
1414
|
-
The workflow has an explicit `trust-gate` job. By default, pull requests from
|
|
1415
|
-
forks fail before any build job can reach self-hosted runners, secrets,
|
|
1416
|
-
publishing credentials, or heavyweight build commands. Same-repository PRs,
|
|
1417
|
-
workflow dispatches, and protected branch events can proceed.
|
|
1418
|
-
|
|
1419
|
-
If a repository wants fork PRs to skip rather than fail, it can set:
|
|
1420
|
-
|
|
1421
|
-
```yaml
|
|
1422
|
-
with:
|
|
1423
|
-
untrusted-policy: skip
|
|
1424
|
-
```
|
|
1425
|
-
|
|
1426
|
-
Do not set `require-trusted-event: false` for workflows that use self-hosted
|
|
1427
|
-
runners or secrets.
|
|
1428
|
-
|
|
1429
|
-
The build matrix and the workflow control plane are routed independently. The
|
|
1430
|
-
matrix continues to use `runner-preset` and `platforms-json`. Consumers with a
|
|
1431
|
-
governed runner may also move channel resolution, trust evaluation, contract
|
|
1432
|
-
resolution, controller evidence, artifact transfer, and aggregation off the
|
|
1433
|
-
default GitHub-hosted runner:
|
|
1434
|
-
|
|
1435
|
-
```yaml
|
|
1436
|
-
with:
|
|
1437
|
-
control-runner-json: '["self-hosted","agent-120"]'
|
|
1438
|
-
runner-preset: custom
|
|
1439
|
-
platforms-json: '[{"id":"linux-x64","name":"Linux x64","runner":"[\"self-hosted\",\"agent-120\"]"}]'
|
|
1440
|
-
```
|
|
1441
|
-
|
|
1442
|
-
`control-runner-json` is additive and defaults to `["ubuntu-24.04"]`. Keep
|
|
1443
|
-
`require-trusted-event: true` whenever either runner input selects
|
|
1444
|
-
`self-hosted`; a self-hosted control plane must not be exposed to untrusted fork
|
|
1445
|
-
events or arbitrary caller-controlled workflow code.
|
|
1446
|
-
|
|
1447
|
-
Consumers that must verify platform-native properties of the final bytes can
|
|
1448
|
-
set `artifact-finalization-command` and `artifact-finalization-on-platform:
|
|
1449
|
-
true`. Buildchain then imports any signed result (or preserves the declared
|
|
1450
|
-
unsigned artifact), runs the command on the matching GitHub-hosted platform,
|
|
1451
|
-
and reseals the manifest before publishing the final deterministic artifact.
|
|
1452
|
-
Platform-native finalization fails closed for self-hosted runners so signing
|
|
1453
|
-
authority credentials and final bytes stay inside the trusted hosted boundary.
|
|
1454
|
-
|
|
1455
|
-
`require-trusted-event` controls access to build runners. It does not override
|
|
1456
|
-
the publish gate: pull requests remain non-publishing events.
|
|
1457
|
-
|
|
1458
|
-
## Fixture
|
|
1459
|
-
|
|
1460
|
-
`fixtures/libnode-shaped` is the contract fixture. It has:
|
|
1461
|
-
|
|
1462
|
-
- `package.json` version state;
|
|
1463
|
-
- `.buildchain/buildchain.toml` with `install`, `build`, `verify`, and `publish`;
|
|
1464
|
-
- cross-platform Node scripts that create small `dist/` outputs;
|
|
1465
|
-
- `Build Surface Fixture` workflow coverage.
|
|
1466
|
-
|
|
1467
|
-
The fixture proves the reusable surface without running the real libnode native
|
|
1468
|
-
build.
|
|
73
|
+
command = "corepack pnpm test"
|
|
74
|
+
|
|
75
|
+
[build]
|
|
76
|
+
environment = "github-hosted"
|
|
77
|
+
timeout_minutes = 120
|
|
78
|
+
fail_fast = false
|
|
79
|
+
|
|
80
|
+
[build.tools]
|
|
81
|
+
node = "24"
|
|
82
|
+
rust = "stable"
|
|
83
|
+
|
|
84
|
+
[build.artifacts]
|
|
85
|
+
name = "my-library"
|
|
86
|
+
paths = ["dist"]
|
|
87
|
+
required_paths = ["dist/library.js"]
|
|
88
|
+
min_files = 1
|
|
89
|
+
release_candidate = true
|
|
90
|
+
retention_days = 14
|
|
91
|
+
compression_level = 0
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Commands remain exclusively in `[lifecycle]`. The backbone explicitly invokes
|
|
95
|
+
install, build and verify in that order on each platform. Build is required;
|
|
96
|
+
install and verify are required when declared. Unneeded stages require no
|
|
97
|
+
additional boolean setting. Per-stage lifecycle timeout declarations retain
|
|
98
|
+
precedence over the build timeout fallback.
|
|
99
|
+
|
|
100
|
+
Artifact paths and required file paths are relative to the selected project.
|
|
101
|
+
Platform artifact names derive from the configured base name,
|
|
102
|
+
platform and source SHA; callers do not supply naming templates. The final
|
|
103
|
+
manifest checks `min_files`, `max_files`, `min_total_bytes` and `required_paths`.
|
|
104
|
+
|
|
105
|
+
Other optional project sections are:
|
|
106
|
+
|
|
107
|
+
| TOML section | Responsibility |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `build.diagnostics` | Process sampling and expected parallelism |
|
|
110
|
+
| `build.verification` | Consumer-produced verify substage evidence location |
|
|
111
|
+
| `build.finalization` | Verification of final signed bytes and platform placement |
|
|
112
|
+
| `build.transport_smoke` | Transport simulation scenario and artifact root |
|
|
113
|
+
| `build.attestation` | Subject path and attested platform |
|
|
114
|
+
| `build.macos_signing` | App path and sealed-input platform |
|
|
115
|
+
| `build.contract` | Compatibility and drift reporting policies |
|
|
116
|
+
| `build.evidence` | Repository files containing gate and candidate-family evidence |
|
|
117
|
+
|
|
118
|
+
Declarative signing targets continue to belong to `[signing.artifacts]`.
|
|
119
|
+
The formal signing authority remains `authority/v3/v3.0/artifact-signing`
|
|
120
|
+
with the protected `buildchain-artifact-signing` environment.
|
|
121
|
+
Credentials, authority profiles and signer identities cannot be supplied through
|
|
122
|
+
that declaration. See [Release Candidate](release-candidate.md)
|
|
123
|
+
and [GitHub Artifact Attestation](github-artifact-attestation.md).
|
|
124
|
+
|
|
125
|
+
## Governed environments
|
|
126
|
+
|
|
127
|
+
`build.environment` selects a profile in
|
|
128
|
+
[`architecture/build-environments.json`](../architecture/build-environments.json)
|
|
129
|
+
from the exact Buildchain runtime. Infrastructure owners maintain runner
|
|
130
|
+
presets/platforms, Linux container images, mirrors, cache transport, artifact
|
|
131
|
+
relay settings and credential-island environments there. Adding a runner label
|
|
132
|
+
or provider role requires reviewing that profile; project TOML cannot redefine
|
|
133
|
+
it. Secrets still cross explicit workflow secret/environment boundaries.
|
|
134
|
+
|
|
135
|
+
The initial profiles are `github-hosted`, `github-hosted-container`,
|
|
136
|
+
`kungfu-v4-native` and `kungfu-v4-self-hosted`. The container profile uses the
|
|
137
|
+
existing digest-pinned `kungfu-verify` image. Native and container jobs remain
|
|
138
|
+
separate because GitHub selects `runs-on` and `container` before executing
|
|
139
|
+
steps. Their shared behavior is owned by these composite actions:
|
|
140
|
+
|
|
141
|
+
| Action | Owner responsibility |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `build-lifecycle-stage` | Lifecycle manifests, sampling and diagnostics |
|
|
144
|
+
| `build-signing-request` | Unsigned requests and detached signing control inputs |
|
|
145
|
+
| `build-verification-evidence` | Independent substage verification and failure evidence |
|
|
146
|
+
| `build-attestation-policy` | Source-bound artifact attestation policy |
|
|
147
|
+
| `build-agent-hub-evidence` | Agent Hub conformance evidence |
|
|
148
|
+
| `build-artifact-transfer` | GitHub and S3 transport plus payload manifests |
|
|
149
|
+
|
|
150
|
+
The backbone still owns install → build → verify order, job dependencies,
|
|
151
|
+
permissions, signing control, credential-island placement and final aggregation.
|
|
152
|
+
A composite's internal receipt inputs transport already resolved facts; they
|
|
153
|
+
are not additional reusable-workflow configuration inputs.
|
|
154
|
+
|
|
155
|
+
## Identity and admission
|
|
156
|
+
|
|
157
|
+
The configuration resolver reads the exact consumer source without executing
|
|
158
|
+
consumer commands. It emits a deterministic plan/root binding configuration
|
|
159
|
+
bytes, source SHA, called-workflow SHA, selected environment, toolchain and
|
|
160
|
+
cache roots. Trust checks run before project execution or privileged runners.
|
|
161
|
+
|
|
162
|
+
Tracked consumer workflows use `@v4` or `@v4-alpha` and commit both
|
|
163
|
+
`.buildchain/contract-lock.json` and `.buildchain/alpha-contract-lock.json`.
|
|
164
|
+
The called channel selects its matching lock. Source-persisted train/SHA
|
|
165
|
+
selectors and mismatched locks remain forbidden. Ordinary builds have no
|
|
166
|
+
runtime-override path; specialized release/recovery entry points keep their
|
|
167
|
+
separate, bounded admission contracts.
|
|
168
|
+
|
|
169
|
+
Bootstrap owns its admitted release and recovery capabilities. It is not an
|
|
170
|
+
alternate parameter envelope for ordinary builds and is not injected into the
|
|
171
|
+
build backbone. Release promotion consumes an already sealed candidate and
|
|
172
|
+
must verify the source, artifacts and receipts independently.
|
|
173
|
+
|
|
174
|
+
## Evidence and failure behavior
|
|
175
|
+
|
|
176
|
+
The workflow retains runtime/source identity, build and diagnostics summaries,
|
|
177
|
+
Release Candidate Passport, signing/finalization and controller receipt outputs.
|
|
178
|
+
The public facade forwards those outputs from the single backbone execution.
|
|
179
|
+
Platform manifests include deterministic payload hashes; transport preserves
|
|
180
|
+
hidden artifacts and provenance. Substage failure evidence is collected even
|
|
181
|
+
when verify fails. Untrusted events cannot reach build runners.
|
|
182
|
+
|
|
183
|
+
Signing authority and credential-island jobs remain separate from ordinary
|
|
184
|
+
build execution. Imported signed bytes undergo consumer verification before
|
|
185
|
+
manifests are recomputed. Release builds produce candidates; registry publishing
|
|
186
|
+
belongs to the protected release path.
|
|
187
|
+
|
|
188
|
+
## Maintaining the contract
|
|
189
|
+
|
|
190
|
+
Update the TOML parser and plan resolver, owner contracts, affected consumers
|
|
191
|
+
and tests together. Run `node scripts/generate-channel-build-workflow.mjs`,
|
|
192
|
+
`pnpm run generate:workflows`, generated reference/site checks and the full
|
|
193
|
+
`pnpm run check`. Breaking input removal is intentional: migrate old `with`
|
|
194
|
+
settings to TOML and remove them from calls; no compatibility forwarding exists.
|
|
195
|
+
|
|
196
|
+
The Buildchain fixture at `fixtures/libnode-shaped/buildchain.toml` exercises
|
|
197
|
+
native macOS/Windows and Linux-container builds through this public contract.
|