@kungfu-tech/buildchain 3.0.8 → 3.0.9-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/promote-buildchain-ref/README.md +8 -7
- package/bin/buildchain.mjs +34 -33
- package/bin/internal/trust-release-release-handlers.mjs +5 -0
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +16 -0
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +57 -0
- package/contracts/release-cut-v1.schema.json +1 -0
- package/contracts/release-train-transition-v1.schema.json +1 -0
- package/dist/site/agent-index.json +0 -1
- package/dist/site/artifact-schemas.json +0 -2
- package/dist/site/badge-endpoint-registry.json +9 -9
- package/dist/site/badges/v1/kfd-8/aligned.json +1 -1
- package/dist/site/badges/v1/kfd-8/declared.json +1 -1
- package/dist/site/badges/v1/kfd-8/downgraded.json +1 -1
- package/dist/site/badges/v1/kfd-8/draft.json +1 -1
- package/dist/site/badges/v1/kfd-8/failed.json +1 -1
- package/dist/site/badges/v1/kfd-8/missing.json +1 -1
- package/dist/site/badges/v1/kfd-8/passed.json +1 -1
- package/dist/site/badges/v1/kfd-8/planned.json +1 -1
- package/dist/site/buildchain-contract.json +38 -34
- package/dist/site/buildchain-site.json +59 -39
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/cli-registry.json +8 -7
- package/dist/site/controller-registry.json +13 -5
- package/dist/site/kfd-claims.json +35 -8
- package/dist/site/kfd-upstream-aggregate.json +10 -10
- package/dist/site/manual-registry.json +9 -9
- package/dist/site/node-api-registry.json +1143 -320
- package/dist/site/page-registry.json +46 -26
- package/dist/site/public-surface-audit.json +19 -9
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-passport-check-manifest.json +33 -5
- package/dist/site/release-provenance.json +2 -1
- package/dist/site/schemas/release-passport-v1.schema.json +3 -0
- package/dist/site/site-manifest.json +13 -13
- package/dist/site/workflow-registry.json +19 -9
- package/docs/aws-us-elastic-runner-burst-plane.md +15 -3
- package/docs/cli-reference.md +6 -6
- package/docs/cli.md +2 -3
- package/docs/dev-alpha-candidate-patrol.md +45 -20
- package/docs/dev-delivery-warrant.md +12 -2
- package/docs/kfd-support.md +7 -7
- package/docs/node-api-reference.md +295 -246
- package/docs/release-passport.md +25 -12
- package/docs/release-train.md +54 -4
- package/docs/reusable-build-surface.md +26 -9
- package/docs/runtime-train-validation.md +6 -0
- package/docs/versioning.md +3 -2
- package/package.json +4 -3
- package/packages/core/artifact-verification-envelope.js +114 -0
- package/packages/core/buildchain-channel-identity.js +119 -0
- package/packages/core/buildchain-compatibility-proof.js +32 -0
- package/packages/core/buildchain-contract.js +7 -0
- package/packages/core/controller-evidence.js +2 -1
- package/packages/core/dev-alpha-active-release-train.js +460 -0
- package/packages/core/dev-alpha-candidate-selection.js +181 -0
- package/packages/core/dev-delivery-warrant.js +15 -4
- package/packages/core/index.js +4 -5
- package/packages/core/kfd-adopter-manifest.js +390 -0
- package/packages/core/kfd-product-gates.js +0 -300
- package/packages/core/release-blocker-priority.js +192 -0
- package/packages/core/release-passport-contract.js +219 -6
- package/packages/core/release-passport.js +139 -242
- package/packages/core/release-train.js +220 -0
- package/scripts/aws-macos-jit-controller-core.mjs +76 -0
- package/scripts/aws-macos-jit-controller.mjs +29 -0
- package/scripts/aws-macos-jit-source-rebind.mjs +503 -0
- package/scripts/buildchain-channel-router.mjs +18 -2
- package/scripts/buildchain-cli-help.mjs +4 -2
- package/scripts/buildchain-contract-lock.mjs +11 -1
- package/scripts/check-inventory.mjs +4 -4
- package/scripts/dev-alpha-candidate-patrol.mjs +196 -201
- package/scripts/generate-buildchain-kfd-witnesses.mjs +88 -94
- package/scripts/generate-channel-build-workflow.mjs +78 -31
- package/scripts/generate-site-bundle.mjs +1 -8
- package/scripts/promotion-channel-router.mjs +5 -3
- package/scripts/release-train-self-dogfood.mjs +579 -0
- package/scripts/runtime-ref-core.mjs +4 -17
- package/scripts/site-capability-metadata.mjs +3 -1
- package/dist/site/schemas/kfd-support-projection-v1.schema.json +0 -106
package/docs/release-passport.md
CHANGED
|
@@ -313,6 +313,13 @@ fails closed if any claim is missing source bindings, machine evidence, hashes,
|
|
|
313
313
|
artifact coordinates, verification result, audit boundary, responsibility, or
|
|
314
314
|
residual risk.
|
|
315
315
|
|
|
316
|
+
The same self-promotion boundary extends the Buildchain-owned KFD witness
|
|
317
|
+
generator against the transaction's exact source SHA. It produces the standard
|
|
318
|
+
full-cut adopter manifest, the non-qualifying KFD-4/5/7 product gates, and the
|
|
319
|
+
one-way legacy projection before the final passport is collected. An explicitly
|
|
320
|
+
supplied adopter manifest still takes precedence; an omitted self-release
|
|
321
|
+
manifest no longer silently produces a KFD-1/2/3-only passport.
|
|
322
|
+
|
|
316
323
|
### KFD-3 collaboration-interface release gate
|
|
317
324
|
|
|
318
325
|
KFD-3 asks a different release question than KFD-1. KFD-1 proves that named
|
|
@@ -399,18 +406,24 @@ instead of trusting docs or release notes.
|
|
|
399
406
|
|
|
400
407
|
### KFD support projection
|
|
401
408
|
|
|
402
|
-
Pass `--kfd-
|
|
403
|
-
`--kfd-product-gate-json` arguments for KFD-4, KFD-5, and
|
|
404
|
-
|
|
405
|
-
`@kungfu-tech/kfd`
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
409
|
+
Pass the standard full-cut declaration with `--kfd-adopter-manifest-json`
|
|
410
|
+
together with three `--kfd-product-gate-json` arguments for KFD-4, KFD-5, and
|
|
411
|
+
KFD-7. The collector invokes the verifier from the exact installed
|
|
412
|
+
`@kungfu-tech/kfd` package, binds the package artifact, registry and verifier
|
|
413
|
+
roots, the exact Buildchain source, the manifest/report/bundle witness roots,
|
|
414
|
+
and the existing product-gate roots. It emits `kfd-adopter-manifest.json`,
|
|
415
|
+
`kfd-adopter-manifest-gate.json`, and a legacy `kfd-support.json` projection.
|
|
416
|
+
The release passport and `artifact-evidence.json` carry the same rooted
|
|
417
|
+
`kfdAdopter` binding.
|
|
418
|
+
|
|
419
|
+
The adopter manifest is the sole declaration authority. The old
|
|
420
|
+
`--kfd-support-matrix-json` input is retained only as a compatibility check: if
|
|
421
|
+
supplied with the manifest, it must exactly equal the generated legacy
|
|
422
|
+
projection. Release verification fails closed when any sibling, package root,
|
|
423
|
+
source root, witness root, gate root, passport binding, or artifact-evidence
|
|
424
|
+
binding differs. A passed binding is release evidence only; product
|
|
425
|
+
qualification, activation, certification, and support ownership remain outside
|
|
426
|
+
Buildchain.
|
|
414
427
|
|
|
415
428
|
### Floating Buildchain contract lock
|
|
416
429
|
|
package/docs/release-train.md
CHANGED
|
@@ -8,12 +8,12 @@ confidence: high
|
|
|
8
8
|
sensitivity: public
|
|
9
9
|
evidence_grade: A
|
|
10
10
|
review_state: self-reviewed
|
|
11
|
-
last_reviewed: 2026-08-
|
|
11
|
+
last_reviewed: 2026-08-11
|
|
12
12
|
ai_provenance:
|
|
13
13
|
model_family: GPT-5
|
|
14
14
|
product: Codex
|
|
15
|
-
generated_at: 2026-08-
|
|
16
|
-
visible_context: Buildchain v3 release candidate, recovery, Dev to Alpha Candidate Patrol, Warrant, publication transaction, and release governance sources.
|
|
15
|
+
generated_at: 2026-08-11
|
|
16
|
+
visible_context: Buildchain v3 release candidate, recovery, Dev to Alpha Candidate Patrol, rooted blocker repair, Warrant, publication transaction, and release governance sources.
|
|
17
17
|
invisible_context_boundary: Live provider state and credentials were not read.
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -38,8 +38,9 @@ own those effects and persist the rooted contract in their declared store.
|
|
|
38
38
|
- a canonical creation timestamp.
|
|
39
39
|
|
|
40
40
|
The resulting `cutRoot` covers all of those fields. A generation greater than
|
|
41
|
-
one must name the prior cut root and one of
|
|
41
|
+
one must name the prior cut root and one of five supersession causes:
|
|
42
42
|
|
|
43
|
+
- `release-blocker-repair` (reserved for the rooted repair contract below);
|
|
43
44
|
- `incompatible-semantics`;
|
|
44
45
|
- `alpha-base-incompatibility`;
|
|
45
46
|
- `invalid-authority`; or
|
|
@@ -74,6 +75,55 @@ an invalid transition fails closed.
|
|
|
74
75
|
changing `trainRoot`, `cutRoot`, candidate identity, generation, or state. The
|
|
75
76
|
same exact observation is idempotent.
|
|
76
77
|
|
|
78
|
+
## Rooted release-blocker repair
|
|
79
|
+
|
|
80
|
+
`createReleaseBlockerRepair()` starts only from the active train's exact
|
|
81
|
+
`repair-required` state root. It creates generation N+1 from the frozen cut,
|
|
82
|
+
changing only the candidate commit and tree while preserving the original Dev
|
|
83
|
+
cut, Alpha base, runtime, route, and prior cut root. The prior train receives an
|
|
84
|
+
explicit `release-blocker-repair` supersession transition; later Dev movement
|
|
85
|
+
alone still cannot advance a generation.
|
|
86
|
+
|
|
87
|
+
The repair binds one semantic patch root to a cut landing and a Dev
|
|
88
|
+
forward-port. A successful cut landing makes the successor candidate buildable
|
|
89
|
+
even while the Dev forward-port is in conflict. Publication remains blocked
|
|
90
|
+
until `settleReleaseBlockerDevLanding()` compare-and-swap checks the repair root
|
|
91
|
+
and records a Dev landing with the same patch root. A landed but different Dev
|
|
92
|
+
patch produces a rooted `cut-dev-patch-root-mismatch` gate rather than
|
|
93
|
+
publication authority.
|
|
94
|
+
|
|
95
|
+
Buildchain v3 Candidate Patrol resolves the open managed candidate's persisted
|
|
96
|
+
train before it considers a new qualified development head. It reads back the
|
|
97
|
+
candidate ref and tree, Alpha base, and exact Buildchain runtime. Matching
|
|
98
|
+
coordinates resume the frozen candidate; a newer development head becomes a
|
|
99
|
+
single rooted observation. Candidate, tree, base, runtime, or route drift emits
|
|
100
|
+
a rooted hold and stops settlement. Only a validated train already carrying an
|
|
101
|
+
enumerated `superseded` transition is reported as superseded.
|
|
102
|
+
|
|
103
|
+
## Buildchain self-dogfood campaign
|
|
104
|
+
|
|
105
|
+
Buildchain qualifies the complete v3 mechanism with
|
|
106
|
+
`scripts/release-train-self-dogfood.mjs`. The campaign composes one frozen
|
|
107
|
+
Release Cut, moving-dev observation, deterministic failed build, successor
|
|
108
|
+
repair, cut/dev patch-root settlement, publication gate, and bounded Delivery
|
|
109
|
+
Warrant priority. It also proves that an active Warrant is not preempted and
|
|
110
|
+
that duplicate events, invalid authority, and unrelated priority claims fail
|
|
111
|
+
closed.
|
|
112
|
+
|
|
113
|
+
The command accepts an exact evidence input and emits a replayable rooted
|
|
114
|
+
report:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
node scripts/release-train-self-dogfood.mjs \
|
|
118
|
+
--input /path/to/exact-protected-delivery.json \
|
|
119
|
+
--output /tmp/buildchain-release-train-self-dogfood.json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
A passing report requires a merged protected PR, exact-head approval,
|
|
123
|
+
merge-group CI success, tree-equivalent merge readback, artifact evidence, and
|
|
124
|
+
installed-product evidence. Synthetic or unit-only evidence is useful for
|
|
125
|
+
negative tests but is not sufficient for release qualification.
|
|
126
|
+
|
|
77
127
|
## Readback and legacy state
|
|
78
128
|
|
|
79
129
|
`validateReleaseCut()` checks the standalone immutable cut and its canonical
|
|
@@ -66,10 +66,25 @@ release events, and non-semver release-like tags fail before the build matrix;
|
|
|
66
66
|
they never guess alpha for a stable release.
|
|
67
67
|
|
|
68
68
|
The router automatically selects `.buildchain/alpha-contract-lock.json` for
|
|
69
|
-
alpha and `.buildchain/contract-lock.json` for stable.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`buildchain-
|
|
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.
|
|
73
88
|
|
|
74
89
|
Only repositories changing the default policy need extra routing input:
|
|
75
90
|
|
|
@@ -279,7 +294,8 @@ shell. The full train validation protocol is documented in
|
|
|
279
294
|
[`runtime-train-validation.md`](runtime-train-validation.md).
|
|
280
295
|
|
|
281
296
|
For one-off manual validation, a trusted maintainer can run the caller workflow
|
|
282
|
-
with a temporary runtime override
|
|
297
|
+
with a temporary runtime override. The override inherits the caller's declared
|
|
298
|
+
alpha or stable lane; trust authorizes the opaque ref, not cross-channel use:
|
|
283
299
|
|
|
284
300
|
```yaml
|
|
285
301
|
on:
|
|
@@ -1092,10 +1108,11 @@ jobs:
|
|
|
1092
1108
|
```
|
|
1093
1109
|
|
|
1094
1110
|
Existing callers may keep `buildchain-contract-lock-path`; a non-empty explicit
|
|
1095
|
-
path overrides channel-specific selection
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1111
|
+
path overrides channel-specific path selection only. Its lock content must
|
|
1112
|
+
still prove the selected channel and major. Migration only requires adding the
|
|
1113
|
+
two channel lock inputs and may retain the remaining common promotion
|
|
1114
|
+
declaration unchanged. Consumers must not call the dot-prefixed advanced
|
|
1115
|
+
workflow directly.
|
|
1099
1116
|
|
|
1100
1117
|
`buildchain-issue-app-id` and `buildchain-issue-app-private-key` are optional
|
|
1101
1118
|
but recommended for cross-repository consumers. They should identify a GitHub
|
|
@@ -165,6 +165,12 @@ maintain, or admin permission on the caller repository. Pull requests,
|
|
|
165
165
|
including fork-originated pull requests, cannot use train or exact-SHA
|
|
166
166
|
overrides.
|
|
167
167
|
|
|
168
|
+
That permission does not create a third channel. A train, authority ref, or
|
|
169
|
+
exact SHA must be bound to an alpha or stable shell lane, and the consumer lock
|
|
170
|
+
must prove that same lane and major. Trusted overrides can replace the runtime
|
|
171
|
+
coordinate for validation; they cannot combine a stable shell or lock with an
|
|
172
|
+
alpha runtime, or the reverse.
|
|
173
|
+
|
|
168
174
|
Runtime train validation covers Buildchain runtime scripts, CLI code, local
|
|
169
175
|
actions, configuration parsing, and lifecycle behavior. It cannot validate
|
|
170
176
|
changes that require the outer reusable workflow YAML itself to change, such as
|
package/docs/versioning.md
CHANGED
|
@@ -79,8 +79,9 @@ repository changes are patch".
|
|
|
79
79
|
|
|
80
80
|
| Date | Action | Line | Faces | Class | Rationale | PR |
|
|
81
81
|
| ---------- | ------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
82
|
-
| 2026-08-
|
|
83
|
-
| 2026-08-
|
|
82
|
+
| 2026-08-11 | extend-minor | `v3.0` | release-blocker-repair-contract, release-blocker-priority-claim, release-train-node-export, dev-delivery-warrant-node-export | additive | Add rooted successor candidate generations on a frozen Release Cut, exact semantic patch identity across cut and Dev landings, publication blocking through conflict or mismatch, and a narrow non-preemptive Warrant blocker lane. | |
|
|
83
|
+
| 2026-08-10 | extend-minor | `v3.0` | release-cut-contract, release-train-state-machine, release-train-node-export | additive | Add a provider-neutral rooted Release Cut and idempotent Release Train state contract that freezes candidate, tree, Alpha base, runtime, generation, and authority while treating later Dev movement as observation rather than implicit supersession. | |
|
|
84
|
+
| 2026-08-05 | extend-minor | `v3.0` | auditable-demo-scenario, auditable-demo-capture, auditable-demo-adapter | additive | Add an opt-in deterministic readable-playback declaration that preserves captured terminal payloads and order while normalizing only presentation timing; omitted playback continues to use observed PTY timestamps, and existing composition modes remain unchanged. | |
|
|
84
85
|
| 2026-08-04 | extend-minor | `v3.0` | dev-delivery-warrant-queue, source-qualification-proof, integration-delivery-proof, dev-delivery-cli, reusable-dev-delivery-workflows | additive | Add durable fair and fenced protected-dev scheduling plus split source/integration proof contracts. Existing PR admission remains available through explicit `off` and `shadow` rollout modes; no existing command, export, or release flow is removed. | |
|
|
85
86
|
| 2026-08-01 | extend-minor | `v3.0` | cli-reference-registry, node-api-symbol-registry, golden-path-manual | additive | Add generated, drift-checked CLI and Node API reference registries to the public site bundle, plus a package-tested first-user Golden Path; existing command execution and import semantics remain unchanged. | |
|
|
86
87
|
| 2026-07-31 | extend-minor | `v3.0` | auditable-demo-workflow, auditable-demo-media-profile, auditable-demo-media-receipt | additive | Add an opt-in responsive profile that binds source-resolution and exact 1280x720 MP4/WebM/GIF renditions to one Gate and receipt while rejecting upscales, aspect-ratio drift, and profile changes between Gate-only and full-render paths. | |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kungfu-tech/buildchain",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.9-alpha.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
|
|
6
6
|
"repository": "https://github.com/kungfu-systems/buildchain",
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"./issue-reporting": "./packages/core/issue-reporting.js",
|
|
34
34
|
"./kfd": "./packages/core/kfd.js",
|
|
35
35
|
"./kfd-product-gates": "./packages/core/kfd-product-gates.js",
|
|
36
|
+
"./kfd-adopter-manifest": "./packages/core/kfd-adopter-manifest.js",
|
|
37
|
+
"./kfd-adopter-release-binding": "./packages/core/artifact-verification-envelope.js",
|
|
36
38
|
"./kfd-agent-hub": "./packages/core/kfd-agent-hub.js",
|
|
37
39
|
"./buildchain-layout": "./packages/core/buildchain-layout.js",
|
|
38
40
|
"./release-line-bootstrap": "./packages/core/release-line-bootstrap.js",
|
|
@@ -87,7 +89,6 @@
|
|
|
87
89
|
"./site/schemas/release-passport-v1.schema.json": "./dist/site/schemas/release-passport-v1.schema.json",
|
|
88
90
|
"./site/schemas/kfd-agent-hub-adoption.schema.json": "./dist/site/schemas/kfd-agent-hub-adoption.schema.json",
|
|
89
91
|
"./site/schemas/kfd-product-gate-input-v1.schema.json": "./dist/site/schemas/kfd-product-gate-input-v1.schema.json",
|
|
90
|
-
"./site/schemas/kfd-support-projection-v1.schema.json": "./dist/site/schemas/kfd-support-projection-v1.schema.json",
|
|
91
92
|
"./site/buildchain-contract.json": "./dist/site/buildchain-contract.json",
|
|
92
93
|
"./site/product-mechanism.json": "./dist/site/product-mechanism.json",
|
|
93
94
|
"./site/release-provenance.json": "./dist/site/release-provenance.json",
|
|
@@ -139,7 +140,7 @@
|
|
|
139
140
|
"typescript": "^5.9.0"
|
|
140
141
|
},
|
|
141
142
|
"dependencies": {
|
|
142
|
-
"@kungfu-tech/kfd": "1.0.0-alpha.
|
|
143
|
+
"@kungfu-tech/kfd": "1.0.0-alpha.60",
|
|
143
144
|
"ajv": "8.20.0",
|
|
144
145
|
"smol-toml": "1.7.0"
|
|
145
146
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
import kfdPackageJson from "@kungfu-tech/kfd/package.json" with { type: "json" };
|
|
3
|
+
import kfdSelfAdopterManifest from "@kungfu-tech/kfd/adopter-conformance/adopters/kfd/manifest.json" with { type: "json" };
|
|
4
|
+
import {
|
|
5
|
+
validateKfdAdopterManifestGate,
|
|
6
|
+
validateKfdLegacySupportMatrixProjection,
|
|
7
|
+
} from "./kfd-adopter-manifest.js";
|
|
8
|
+
import { kfdProductGateDigest } from "./kfd-product-gates.js";
|
|
2
9
|
|
|
3
10
|
export const ARTIFACT_VERIFICATION_ENVELOPE_CONTRACT =
|
|
4
11
|
"kungfu-buildchain-artifact-verification-envelope";
|
|
@@ -6,6 +13,8 @@ export const ARTIFACT_VERIFICATION_ENVELOPE_CHECK_CONTRACT =
|
|
|
6
13
|
"kungfu-buildchain-artifact-verification-envelope-check";
|
|
7
14
|
export const KFX_ADMISSION_INPUTS_CONTRACT =
|
|
8
15
|
"kungfu-buildchain-kfx-admission-inputs";
|
|
16
|
+
export const KFD_ADOPTER_RELEASE_BINDING_CONTRACT =
|
|
17
|
+
"kungfu-buildchain-kfd-adopter-release-binding";
|
|
9
18
|
|
|
10
19
|
const ARTIFACT_VERIFICATION_CONTRACT =
|
|
11
20
|
"kungfu-buildchain-artifact-verification";
|
|
@@ -384,3 +393,108 @@ export function projectArtifactVerificationEnvelopeToKfx({
|
|
|
384
393
|
kfdAssessment: jsonClone(envelope.kfdAssessment),
|
|
385
394
|
};
|
|
386
395
|
}
|
|
396
|
+
|
|
397
|
+
export function installedKfdPackageArtifactRoot() {
|
|
398
|
+
const cut = kfdSelfAdopterManifest?.kfdCut?.package;
|
|
399
|
+
if (cut?.name !== kfdPackageJson.name || cut?.version !== kfdPackageJson.version
|
|
400
|
+
|| !SHA256_PATTERN.test(String(cut?.artifactRoot || ""))) {
|
|
401
|
+
throw new Error("installed KFD package does not expose a matching rooted self-adopter package cut");
|
|
402
|
+
}
|
|
403
|
+
return cut.artifactRoot;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function kfdBindingBody({ manifest, manifestGate, legacyProjection, paths }) {
|
|
407
|
+
return {
|
|
408
|
+
schemaVersion: 1,
|
|
409
|
+
contract: KFD_ADOPTER_RELEASE_BINDING_CONTRACT,
|
|
410
|
+
status: "passed",
|
|
411
|
+
qualifying: false,
|
|
412
|
+
selfCertified: false,
|
|
413
|
+
authority: {
|
|
414
|
+
manifestPath: paths.manifest,
|
|
415
|
+
manifestContract: manifest.contract,
|
|
416
|
+
manifestRoot: manifestGate.authority.manifestRoot,
|
|
417
|
+
gatePath: paths.gate,
|
|
418
|
+
gateRoot: manifestGate.gateRoot,
|
|
419
|
+
},
|
|
420
|
+
source: jsonClone(manifestGate.source),
|
|
421
|
+
standardPackage: jsonClone(manifestGate.standardPackage),
|
|
422
|
+
witness: {
|
|
423
|
+
decisionRoot: manifestGate.decisionWitness.root,
|
|
424
|
+
verificationReportRoot: manifestGate.manifestVerificationReportRoot,
|
|
425
|
+
bundleRoot: manifestGate.manifestBundleRoot,
|
|
426
|
+
},
|
|
427
|
+
legacyProjection: {
|
|
428
|
+
path: paths.legacy,
|
|
429
|
+
contract: legacyProjection.contract,
|
|
430
|
+
root: kfdProductGateDigest(legacyProjection),
|
|
431
|
+
authorityRoot: legacyProjection.authority.root,
|
|
432
|
+
gateRoot: legacyProjection.authority.gateRoot,
|
|
433
|
+
},
|
|
434
|
+
nonClaims: [
|
|
435
|
+
"This binding proves exact release-envelope consumption, not KFD certification or release authorization.",
|
|
436
|
+
"The legacy support matrix remains a projection of the standard adopter manifest authority.",
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export function createKfdAdopterReleaseBinding({
|
|
442
|
+
manifest,
|
|
443
|
+
manifestGate,
|
|
444
|
+
legacyProjection,
|
|
445
|
+
manifestPath = "kfd-adopter-manifest.json",
|
|
446
|
+
gatePath = "kfd-adopter-manifest-gate.json",
|
|
447
|
+
legacyProjectionPath = "kfd-support.json",
|
|
448
|
+
expectedSourceSha = "",
|
|
449
|
+
} = {}) {
|
|
450
|
+
const gate = validateKfdAdopterManifestGate(manifestGate, {
|
|
451
|
+
expectedSourceSha,
|
|
452
|
+
checkedAt: manifestGate?.checkedAt,
|
|
453
|
+
});
|
|
454
|
+
const legacy = validateKfdLegacySupportMatrixProjection(legacyProjection, { manifest, manifestGate });
|
|
455
|
+
if (!gate.valid || !legacy.valid) {
|
|
456
|
+
throw new Error(`KFD adopter release binding inputs are invalid: ${JSON.stringify([...gate.issues, ...legacy.issues])}`);
|
|
457
|
+
}
|
|
458
|
+
const body = kfdBindingBody({
|
|
459
|
+
manifest,
|
|
460
|
+
manifestGate,
|
|
461
|
+
legacyProjection,
|
|
462
|
+
paths: { manifest: manifestPath, gate: gatePath, legacy: legacyProjectionPath },
|
|
463
|
+
});
|
|
464
|
+
return { ...body, bindingRoot: kfdProductGateDigest(body) };
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export function validateKfdAdopterReleaseBinding(binding, {
|
|
468
|
+
manifest,
|
|
469
|
+
manifestGate,
|
|
470
|
+
legacyProjection,
|
|
471
|
+
expectedSourceSha = "",
|
|
472
|
+
} = {}) {
|
|
473
|
+
const issues = [];
|
|
474
|
+
if (!binding || binding.schemaVersion !== 1 || binding.contract !== KFD_ADOPTER_RELEASE_BINDING_CONTRACT) {
|
|
475
|
+
return { valid: false, issues: [{ code: "adopter-release-binding-contract", path: "", message: `binding must use ${KFD_ADOPTER_RELEASE_BINDING_CONTRACT} v1` }] };
|
|
476
|
+
}
|
|
477
|
+
const copy = jsonClone(binding);
|
|
478
|
+
const bindingRoot = copy.bindingRoot;
|
|
479
|
+
delete copy.bindingRoot;
|
|
480
|
+
if (bindingRoot !== kfdProductGateDigest(copy)) {
|
|
481
|
+
issues.push({ code: "adopter-release-binding-root", path: "bindingRoot", message: "release binding root does not match its content" });
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
const expected = createKfdAdopterReleaseBinding({
|
|
485
|
+
manifest,
|
|
486
|
+
manifestGate,
|
|
487
|
+
legacyProjection,
|
|
488
|
+
manifestPath: binding.authority?.manifestPath,
|
|
489
|
+
gatePath: binding.authority?.gatePath,
|
|
490
|
+
legacyProjectionPath: binding.legacyProjection?.path,
|
|
491
|
+
expectedSourceSha,
|
|
492
|
+
});
|
|
493
|
+
if (stableJson(binding) !== stableJson(expected)) {
|
|
494
|
+
issues.push({ code: "adopter-release-binding-drift", path: "", message: "release binding differs from the exact manifest, gate, or legacy projection closure" });
|
|
495
|
+
}
|
|
496
|
+
} catch (error) {
|
|
497
|
+
issues.push({ code: "adopter-release-binding-authority", path: "", message: error.message });
|
|
498
|
+
}
|
|
499
|
+
return { valid: issues.length === 0, issues };
|
|
500
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const EXACT_SHA_RE = /^[0-9a-f]{40}$/i;
|
|
2
|
+
const OFFICIAL_REF_RE = /^v(\d+)(?:\.\d+)?(-alpha)?$/;
|
|
3
|
+
const STABLE_RELEASE_RE = /^v(\d+)\.\d+\.\d+$/;
|
|
4
|
+
const ALPHA_RELEASE_RE = /^v(\d+)\.\d+\.\d+-alpha\.\d+$/;
|
|
5
|
+
const TRAIN_REF_RE = /^train\/v(\d+)\/v(\d+)\.\d+\/[A-Za-z0-9._/-]+$/;
|
|
6
|
+
const AUTHORITY_REF_RE = /^authority\/v(\d+)\/v(\d+)\.\d+\/[A-Za-z0-9._/-]+$/;
|
|
7
|
+
|
|
8
|
+
export const BUILDCHAIN_CHANNELS = new Set(["stable", "alpha"]);
|
|
9
|
+
|
|
10
|
+
export function normalizeBuildchainRef(ref = "") {
|
|
11
|
+
const value = String(ref || "").trim();
|
|
12
|
+
const workflowRef = value.includes("/.github/workflows/") ? value.split("@").pop() || "" : value;
|
|
13
|
+
return workflowRef.replace(/^refs\/(?:heads|tags)\//, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function parseBuildchainRefIdentity(ref = "") {
|
|
17
|
+
const value = normalizeBuildchainRef(ref);
|
|
18
|
+
if (!value) return { ref: value, kind: "missing", channel: null, major: null };
|
|
19
|
+
if (EXACT_SHA_RE.test(value)) return { ref: value, kind: "exact-sha", channel: null, major: null };
|
|
20
|
+
|
|
21
|
+
for (const [pattern, channel, kind] of [
|
|
22
|
+
[OFFICIAL_REF_RE, null, "official-channel"],
|
|
23
|
+
[STABLE_RELEASE_RE, "stable", "release"],
|
|
24
|
+
[ALPHA_RELEASE_RE, "alpha", "release"],
|
|
25
|
+
]) {
|
|
26
|
+
const match = value.match(pattern);
|
|
27
|
+
if (match) {
|
|
28
|
+
return {
|
|
29
|
+
ref: value,
|
|
30
|
+
kind,
|
|
31
|
+
channel: channel || (match[2] ? "alpha" : "stable"),
|
|
32
|
+
major: Number(match[1]),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const [pattern, kind] of [
|
|
38
|
+
[TRAIN_REF_RE, "train"],
|
|
39
|
+
[AUTHORITY_REF_RE, "authority"],
|
|
40
|
+
]) {
|
|
41
|
+
const match = value.match(pattern);
|
|
42
|
+
if (match) {
|
|
43
|
+
return {
|
|
44
|
+
ref: value,
|
|
45
|
+
kind,
|
|
46
|
+
channel: null,
|
|
47
|
+
major: Number(match[1]),
|
|
48
|
+
coherentMajor: match[1] === match[2],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { ref: value, kind: "development", channel: null, major: null };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function expectedIdentity({ workflowShellRef, expectedChannel, expectedMajor }) {
|
|
56
|
+
const shell = parseBuildchainRefIdentity(workflowShellRef);
|
|
57
|
+
const channel =
|
|
58
|
+
String(expectedChannel || "")
|
|
59
|
+
.trim()
|
|
60
|
+
.toLowerCase() || shell.channel;
|
|
61
|
+
const majorText = String(expectedMajor ?? "").trim();
|
|
62
|
+
const major = majorText ? Number(majorText.replace(/^v/, "")) : shell.major;
|
|
63
|
+
return { shell, channel, major };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function expectedReasons(expected, { expectedChannel, expectedMajor }) {
|
|
67
|
+
const reasons = [];
|
|
68
|
+
if (!BUILDCHAIN_CHANNELS.has(expected.channel)) reasons.push("Buildchain channel is missing or ambiguous");
|
|
69
|
+
if (!Number.isInteger(expected.major) || expected.major < 1) reasons.push("Buildchain major is missing or ambiguous");
|
|
70
|
+
if (expected.shell.channel && expected.shell.channel !== expected.channel) {
|
|
71
|
+
reasons.push(`workflow shell ${expected.shell.ref} is ${expected.shell.channel}, expected ${expected.channel}`);
|
|
72
|
+
}
|
|
73
|
+
if (Number.isInteger(expected.shell.major) && expected.shell.major !== expected.major) {
|
|
74
|
+
reasons.push(`workflow shell ${expected.shell.ref} is v${expected.shell.major}, expected v${expected.major}`);
|
|
75
|
+
}
|
|
76
|
+
if (!expected.shell.channel && (!expectedChannel || !expectedMajor)) {
|
|
77
|
+
reasons.push(`workflow shell ${expected.shell.ref || "(missing)"} does not declare a stable or alpha channel`);
|
|
78
|
+
}
|
|
79
|
+
return reasons;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function runtimeReasons(expected, runtime, allowOpaqueRuntime) {
|
|
83
|
+
if (runtime.channel) {
|
|
84
|
+
return [runtime.channel !== expected.channel ? `runtime ${runtime.ref} is ${runtime.channel}, expected ${expected.channel}` : "", runtime.major !== expected.major ? `runtime ${runtime.ref} is v${runtime.major}, expected v${expected.major}` : ""].filter(Boolean);
|
|
85
|
+
}
|
|
86
|
+
if (new Set(["train", "authority", "exact-sha"]).has(runtime.kind) && allowOpaqueRuntime) {
|
|
87
|
+
return [runtime.coherentMajor === false ? `runtime ${runtime.ref} has inconsistent major segments` : "", Number.isInteger(runtime.major) && runtime.major !== expected.major ? `runtime ${runtime.ref} is v${runtime.major}, expected v${expected.major}` : ""].filter(Boolean);
|
|
88
|
+
}
|
|
89
|
+
return [`runtime ${runtime.ref || "(missing)"} does not prove the ${expected.channel || "selected"} channel`];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function lockReasons(expected, lock, lockMajor, lockMajorLine) {
|
|
93
|
+
if (!lock.ref) return ["Buildchain contract lock is required for a channel-bound run"];
|
|
94
|
+
return [lock.channel !== expected.channel ? `contract lock ref ${lock.ref} does not prove the ${expected.channel} channel` : "", lock.major !== expected.major ? `contract lock ref ${lock.ref} does not prove major v${expected.major}` : "", lockMajorLine && lockMajor.major !== expected.major ? `contract lock major line ${lockMajor.ref} does not match v${expected.major}` : ""].filter(Boolean);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function evaluateBuildchainChannelBinding({ workflowShellRef = "", runtimeRef = "", lockRef = "", lockMajorLine = "", expectedChannel = "", expectedMajor = "", allowOpaqueRuntime = false } = {}) {
|
|
98
|
+
const expected = expectedIdentity({
|
|
99
|
+
workflowShellRef,
|
|
100
|
+
expectedChannel,
|
|
101
|
+
expectedMajor,
|
|
102
|
+
});
|
|
103
|
+
const runtime = parseBuildchainRefIdentity(runtimeRef);
|
|
104
|
+
const lock = parseBuildchainRefIdentity(lockRef);
|
|
105
|
+
const lockMajor = parseBuildchainRefIdentity(lockMajorLine);
|
|
106
|
+
const reasons = [...expectedReasons(expected, { expectedChannel, expectedMajor }), ...runtimeReasons(expected, runtime, allowOpaqueRuntime), ...lockReasons(expected, lock, lockMajor, lockMajorLine)];
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
ok: reasons.length === 0,
|
|
110
|
+
status: reasons.length === 0 ? "channel-bound" : "channel-binding-mismatch",
|
|
111
|
+
channel: expected.channel || null,
|
|
112
|
+
major: Number.isInteger(expected.major) ? expected.major : null,
|
|
113
|
+
shell: expected.shell,
|
|
114
|
+
runtime,
|
|
115
|
+
lock,
|
|
116
|
+
lockMajor,
|
|
117
|
+
reasons,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
devDeliveryRepository as repository,
|
|
8
8
|
devDeliveryText as text,
|
|
9
9
|
} from "./dev-delivery-common.js";
|
|
10
|
+
import { evaluateBuildchainChannelBinding } from "./buildchain-channel-identity.js";
|
|
10
11
|
|
|
11
12
|
export const BUILDCHAIN_COMPATIBILITY_PROOF_SCHEMA = "kungfu.buildchain.compatibility-proof/v1";
|
|
12
13
|
export const BUILDCHAIN_COMPATIBILITY_PROOF_REGISTRY_SCHEMA = "kungfu.buildchain.compatibility-proof-registry/v1";
|
|
@@ -437,6 +438,19 @@ function evaluateSurfaceRelation({ oldSurface, nextSurface, proofRegistry, major
|
|
|
437
438
|
};
|
|
438
439
|
}
|
|
439
440
|
|
|
441
|
+
function evaluateChannelBinding({ lock, workflowShellRef, runtimeRef, expectedChannel, expectedMajor, allowOpaqueRuntime }) {
|
|
442
|
+
if (!workflowShellRef && !expectedChannel && !expectedMajor) return null;
|
|
443
|
+
return evaluateBuildchainChannelBinding({
|
|
444
|
+
workflowShellRef,
|
|
445
|
+
runtimeRef,
|
|
446
|
+
lockRef: lock?.buildchain?.ref || "",
|
|
447
|
+
lockMajorLine: lock?.buildchain?.majorLine || "",
|
|
448
|
+
expectedChannel,
|
|
449
|
+
expectedMajor,
|
|
450
|
+
allowOpaqueRuntime,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
440
454
|
export function evaluateBuildchainContractLock({
|
|
441
455
|
lock,
|
|
442
456
|
current,
|
|
@@ -444,11 +458,29 @@ export function evaluateBuildchainContractLock({
|
|
|
444
458
|
runtimeSha = "",
|
|
445
459
|
runtimeClass = "",
|
|
446
460
|
compatibilityPolicy = "",
|
|
461
|
+
workflowShellRef = "",
|
|
462
|
+
expectedChannel = "",
|
|
463
|
+
expectedMajor = "",
|
|
464
|
+
allowOpaqueRuntime = false,
|
|
447
465
|
} = {}) {
|
|
448
466
|
if (!current || current.contract !== BUILDCHAIN_CONTRACT) {
|
|
449
467
|
throw new Error("current must be a Buildchain runtime contract world");
|
|
450
468
|
}
|
|
451
469
|
assertBuildchainCompatibilityProjection(current);
|
|
470
|
+
const binding = evaluateChannelBinding({
|
|
471
|
+
lock, workflowShellRef, runtimeRef, expectedChannel, expectedMajor, allowOpaqueRuntime,
|
|
472
|
+
});
|
|
473
|
+
if (binding?.ok === false) {
|
|
474
|
+
return {
|
|
475
|
+
ok: false,
|
|
476
|
+
status: binding.status,
|
|
477
|
+
drift: false,
|
|
478
|
+
compatible: false,
|
|
479
|
+
issueRecommended: false,
|
|
480
|
+
reasons: binding.reasons,
|
|
481
|
+
channelBinding: binding,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
452
484
|
if (!new Set(["stable", "alpha"]).has(runtimeClass)) {
|
|
453
485
|
return {
|
|
454
486
|
ok: true,
|
|
@@ -9,6 +9,13 @@ import {
|
|
|
9
9
|
import { createControllerRegistry } from "./controller-evidence.js";
|
|
10
10
|
import { enumerateWorkflowInputs } from "./public-surface-audit.js";
|
|
11
11
|
|
|
12
|
+
export {
|
|
13
|
+
BUILDCHAIN_CHANNELS,
|
|
14
|
+
evaluateBuildchainChannelBinding,
|
|
15
|
+
normalizeBuildchainRef,
|
|
16
|
+
parseBuildchainRefIdentity,
|
|
17
|
+
} from "./buildchain-channel-identity.js";
|
|
18
|
+
|
|
12
19
|
export {
|
|
13
20
|
BUILDCHAIN_COMPATIBILITY_PROOF_REGISTRY_SCHEMA,
|
|
14
21
|
BUILDCHAIN_COMPATIBILITY_PROOF_SCHEMA,
|
|
@@ -53,7 +53,8 @@ const CONTROLLER_SPECS = [
|
|
|
53
53
|
workflowId: "build",
|
|
54
54
|
version: 1,
|
|
55
55
|
capabilities: ["channel-selection", "runtime-selection", "build-delegation"],
|
|
56
|
-
stages: ["resolve-channel", "
|
|
56
|
+
stages: ["resolve-channel", "alpha", "stable", "aggregate"],
|
|
57
|
+
optionalStages: ["alpha", "stable"],
|
|
57
58
|
evidence: ["nested-controller-receipt", "controller-receipt"],
|
|
58
59
|
},
|
|
59
60
|
{
|