@kungfu-tech/buildchain 3.0.8 → 3.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.
Files changed (57) hide show
  1. package/actions/promote-buildchain-ref/README.md +8 -7
  2. package/bin/buildchain.mjs +34 -33
  3. package/bin/internal/trust-release-release-handlers.mjs +5 -0
  4. package/dist/site/agent-index.json +0 -1
  5. package/dist/site/artifact-schemas.json +0 -2
  6. package/dist/site/badge-endpoint-registry.json +9 -9
  7. package/dist/site/badges/v1/kfd-8/aligned.json +1 -1
  8. package/dist/site/badges/v1/kfd-8/declared.json +1 -1
  9. package/dist/site/badges/v1/kfd-8/downgraded.json +1 -1
  10. package/dist/site/badges/v1/kfd-8/draft.json +1 -1
  11. package/dist/site/badges/v1/kfd-8/failed.json +1 -1
  12. package/dist/site/badges/v1/kfd-8/missing.json +1 -1
  13. package/dist/site/badges/v1/kfd-8/passed.json +1 -1
  14. package/dist/site/badges/v1/kfd-8/planned.json +1 -1
  15. package/dist/site/buildchain-contract.json +27 -22
  16. package/dist/site/buildchain-site.json +38 -28
  17. package/dist/site/capability-registry.json +1 -1
  18. package/dist/site/cli-registry.json +8 -7
  19. package/dist/site/controller-registry.json +6 -2
  20. package/dist/site/kfd-claims.json +34 -7
  21. package/dist/site/kfd-upstream-aggregate.json +10 -10
  22. package/dist/site/manual-registry.json +6 -6
  23. package/dist/site/node-api-registry.json +754 -228
  24. package/dist/site/page-registry.json +28 -18
  25. package/dist/site/public-surface-audit.json +19 -9
  26. package/dist/site/publication-registry.json +4 -4
  27. package/dist/site/release-passport-check-manifest.json +33 -5
  28. package/dist/site/release-provenance.json +2 -1
  29. package/dist/site/schemas/release-passport-v1.schema.json +3 -0
  30. package/dist/site/site-manifest.json +10 -10
  31. package/dist/site/workflow-registry.json +19 -9
  32. package/docs/aws-us-elastic-runner-burst-plane.md +15 -3
  33. package/docs/cli-reference.md +6 -6
  34. package/docs/cli.md +2 -3
  35. package/docs/dev-alpha-candidate-patrol.md +45 -20
  36. package/docs/kfd-support.md +7 -7
  37. package/docs/node-api-reference.md +179 -140
  38. package/docs/release-passport.md +18 -12
  39. package/docs/release-train.md +8 -0
  40. package/package.json +4 -3
  41. package/packages/core/artifact-verification-envelope.js +114 -0
  42. package/packages/core/dev-alpha-active-release-train.js +460 -0
  43. package/packages/core/dev-alpha-candidate-selection.js +181 -0
  44. package/packages/core/index.js +4 -5
  45. package/packages/core/kfd-adopter-manifest.js +390 -0
  46. package/packages/core/kfd-product-gates.js +0 -300
  47. package/packages/core/release-passport-contract.js +219 -6
  48. package/packages/core/release-passport.js +139 -242
  49. package/scripts/aws-macos-jit-controller-core.mjs +76 -0
  50. package/scripts/aws-macos-jit-controller.mjs +29 -0
  51. package/scripts/aws-macos-jit-source-rebind.mjs +503 -0
  52. package/scripts/buildchain-cli-help.mjs +4 -2
  53. package/scripts/check-inventory.mjs +2 -2
  54. package/scripts/dev-alpha-candidate-patrol.mjs +196 -201
  55. package/scripts/generate-site-bundle.mjs +1 -8
  56. package/scripts/site-capability-metadata.mjs +3 -1
  57. package/dist/site/schemas/kfd-support-projection-v1.schema.json +0 -106
@@ -10,12 +10,8 @@ export const KFD_PRODUCT_GATE_INPUT_CONTRACT =
10
10
  "kungfu-buildchain-kfd-product-gate-input";
11
11
  export const KFD_PRODUCT_GATE_CONTRACT =
12
12
  "kungfu-buildchain-kfd-product-gate";
13
- export const KFD_SUPPORT_PROJECTION_CONTRACT =
14
- "kungfu-buildchain-kfd-support-projection";
15
13
  export const KFD_PRODUCT_GATE_INPUT_SCHEMA_ID =
16
14
  "https://buildchain.libkungfu.dev/schemas/kfd-product-gate-input-v1.schema.json";
17
- export const KFD_SUPPORT_PROJECTION_SCHEMA_ID =
18
- "https://buildchain.libkungfu.dev/schemas/kfd-support-projection-v1.schema.json";
19
15
 
20
16
  const SUPPORTED_GATE_STANDARDS = Object.freeze(["kfd-4", "kfd-5", "kfd-7"]);
21
17
  const SUPPORTED_GATE_STANDARD_SET = new Set(SUPPORTED_GATE_STANDARDS);
@@ -127,48 +123,6 @@ export const KFD_PRODUCT_GATE_INPUT_SCHEMA = {
127
123
  },
128
124
  };
129
125
 
130
- export const KFD_SUPPORT_PROJECTION_SCHEMA = {
131
- $schema: "https://json-schema.org/draft/2020-12/schema",
132
- $id: KFD_SUPPORT_PROJECTION_SCHEMA_ID,
133
- title: "Buildchain KFD support projection v1",
134
- description:
135
- "A release-bound, non-authoritative projection of one product-owned KFD support matrix.",
136
- type: "object",
137
- additionalProperties: false,
138
- required: [
139
- "schemaVersion",
140
- "contract",
141
- "matrix",
142
- "standardPackage",
143
- "gateResults",
144
- "rows",
145
- "status",
146
- "projectionRoot",
147
- "nonClaims",
148
- ],
149
- properties: {
150
- schemaVersion: { const: 1 },
151
- contract: { const: KFD_SUPPORT_PROJECTION_CONTRACT },
152
- matrix: {
153
- type: "object",
154
- additionalProperties: false,
155
- required: ["contract", "root", "authorityPath"],
156
- properties: { contract: STRING, root: SHA256, authorityPath: STRING },
157
- },
158
- standardPackage: {
159
- type: "object",
160
- additionalProperties: false,
161
- required: ["name", "version", "standardsSha256"],
162
- properties: { name: STRING, version: STRING, standardsSha256: SHA256 },
163
- },
164
- gateResults: { type: "array", minItems: 3, items: { type: "object" } },
165
- rows: { type: "array", minItems: 13, maxItems: 13, items: { type: "object" } },
166
- status: { enum: ["passed", "failed"] },
167
- projectionRoot: SHA256,
168
- nonClaims: { type: "array", minItems: 1, items: STRING },
169
- },
170
- };
171
-
172
126
  const require = createRequire(import.meta.url);
173
127
  let verifierPromise;
174
128
 
@@ -604,262 +558,8 @@ export function validateKfdProductGateResult(result, {
604
558
  return { valid: issues.length === 0, issues };
605
559
  }
606
560
 
607
- function expectedKfdIds() {
608
- return Array.from({ length: 13 }, (_, index) => `KFD-${index + 1}`);
609
- }
610
-
611
- function normalizeMatrixRoot(matrix, matrixRoot) {
612
- const normalized = normalizeSha256(matrixRoot);
613
- return normalized || kfdProductGateDigest(matrix);
614
- }
615
-
616
- function projectMatrixRow(row) {
617
- return {
618
- id: row.id,
619
- key: row.key,
620
- title: row.title,
621
- supportStatus: row.supportStatus,
622
- normative: row.normative,
623
- implementation: row.implementation,
624
- verification: row.verification,
625
- buildchain: row.buildchain,
626
- releaseQualification: row.releaseQualification,
627
- claimClass: row.claimClass,
628
- knownLimitations: row.knownLimitations,
629
- owner: row.owner,
630
- nextGate: row.nextGate,
631
- };
632
- }
633
-
634
- function validateMatrixRows(matrix, gatesByStandard, issues) {
635
- const rows = Array.isArray(matrix?.rows) ? matrix.rows : [];
636
- const expectedIds = expectedKfdIds();
637
- const ids = rows.map((row) => row?.id);
638
- if (rows.length !== expectedIds.length || new Set(ids).size !== expectedIds.length) {
639
- issues.push(issue("matrix-row-set", "rows", "support matrix must contain exactly one row for KFD-1 through KFD-13"));
640
- }
641
- for (const id of expectedIds) {
642
- const row = rows.find((entry) => entry?.id === id);
643
- if (!row) {
644
- issues.push(issue("matrix-row-missing", "rows", `${id} is missing`));
645
- continue;
646
- }
647
- const key = id.toLowerCase();
648
- const metadata = standardMetadata(key);
649
- if (row.key !== key || row?.normative?.status !== metadata.status || row?.normative?.revision !== metadata.revision) {
650
- issues.push(issue("matrix-normative-drift", `rows.${id}.normative`, `${id} must match installed KFD status and revision`, {
651
- expected: { key, status: metadata.status, revision: metadata.revision },
652
- actual: { key: row.key, status: row?.normative?.status, revision: row?.normative?.revision },
653
- }));
654
- }
655
- const shipped = row?.releaseQualification?.shippedSupport === true;
656
- if (
657
- shipped &&
658
- (
659
- row?.implementation?.status !== "implemented" ||
660
- row?.verification?.status !== "passed" ||
661
- row?.buildchain?.gateStatus !== "passed" ||
662
- !String(row.supportStatus || "").includes("supported")
663
- )
664
- ) {
665
- issues.push(issue("matrix-shipped-widening", `rows.${id}`, `${id} cannot be shipped without implemented, verified, and passed Buildchain evidence`));
666
- }
667
- }
668
- for (const id of ["KFD-4", "KFD-5"]) {
669
- const row = rows.find((entry) => entry?.id === id);
670
- if (row?.supportStatus !== "candidate" || row?.releaseQualification?.shippedSupport !== false) {
671
- issues.push(issue("matrix-candidate-widening", `rows.${id}`, `${id} must remain a non-shipped candidate`));
672
- }
673
- }
674
- const kfd6 = rows.find((entry) => entry?.id === "KFD-6");
675
- if (
676
- kfd6?.supportStatus !== "unsupported" ||
677
- kfd6?.releaseQualification?.shippedSupport !== false ||
678
- kfd6?.buildchain?.gateStatus === "passed"
679
- ) {
680
- issues.push(issue("matrix-kfd6-barrier", "rows.KFD-6", "KFD-6 must remain explicitly unsupported and non-shipped"));
681
- }
682
- for (let number = 8; number <= 13; number += 1) {
683
- const id = `KFD-${number}`;
684
- const row = rows.find((entry) => entry?.id === id);
685
- if (
686
- row?.supportStatus !== "draft-adopter-evidence" ||
687
- row?.releaseQualification?.shippedSupport !== false ||
688
- row?.buildchain?.gateStatus === "passed"
689
- ) {
690
- issues.push(issue("matrix-draft-barrier", `rows.${id}`, `${id} must remain draft adopter evidence and non-shipped`));
691
- }
692
- }
693
- for (const standard of SUPPORTED_GATE_STANDARDS) {
694
- const id = standard.toUpperCase();
695
- const row = rows.find((entry) => entry?.id === id);
696
- const gate = gatesByStandard.get(standard);
697
- if (!gate) {
698
- issues.push(issue("matrix-gate-missing", `rows.${id}.buildchain`, `${id} requires a Buildchain product-gate result`));
699
- continue;
700
- }
701
- const rowPassed = row?.buildchain?.gateStatus === "passed";
702
- const gatePassed = gate.status === "passed";
703
- if (rowPassed !== gatePassed) {
704
- issues.push(issue("matrix-gate-disagreement", `rows.${id}.buildchain.gateStatus`, `${id} matrix and Buildchain gate disagree`, {
705
- matrix: row?.buildchain?.gateStatus,
706
- gate: gate.status,
707
- }));
708
- }
709
- if (row?.buildchain?.protocol !== `${KFD_PRODUCT_GATE_CONTRACT}/v1`) {
710
- issues.push(issue("matrix-gate-protocol", `rows.${id}.buildchain.protocol`, `${id} must name the versioned Buildchain product-gate protocol`));
711
- }
712
- }
713
- return rows;
714
- }
715
-
716
- export function createKfdSupportProjection({
717
- matrix,
718
- matrixRoot = "",
719
- gateResults = [],
720
- authorityPath = ".buildchain/kfd/support-matrix.json",
721
- expectedSourceSha = "",
722
- checkedAt = new Date().toISOString(),
723
- } = {}) {
724
- const issues = [];
725
- if (!isObject(matrix) || matrix.contract !== "kungfu-kfd-support-matrix" || matrix.schemaVersion !== 1) {
726
- issues.push(issue("matrix-contract", "", "support matrix must use kungfu-kfd-support-matrix v1"));
727
- }
728
- if (
729
- matrix?.upstream?.package !== kfdPackageJson.name ||
730
- matrix?.upstream?.version !== kfdPackageJson.version ||
731
- matrix?.upstream?.standardsSha256 !== standardsFileDigest()
732
- ) {
733
- issues.push(issue("matrix-standard-package", "upstream", "support matrix must bind the installed KFD package and standards bytes", {
734
- expected: {
735
- package: kfdPackageJson.name,
736
- version: kfdPackageJson.version,
737
- standardsSha256: standardsFileDigest(),
738
- },
739
- actual: matrix?.upstream,
740
- }));
741
- }
742
- const gatesByStandard = new Map();
743
- for (const [index, gate] of gateResults.entries()) {
744
- const validation = validateKfdProductGateResult(gate, { expectedSourceSha, checkedAt });
745
- if (!validation.valid) {
746
- issues.push(issue("gate-result-invalid", `gateResults[${index}]`, "gate result is invalid", {
747
- gateIssues: validation.issues,
748
- }));
749
- }
750
- if (gatesByStandard.has(gate?.standard)) {
751
- issues.push(issue("gate-result-duplicate", `gateResults[${index}].standard`, `${gate.standard} gate result is duplicated`));
752
- }
753
- gatesByStandard.set(gate?.standard, gate);
754
- }
755
- const rows = validateMatrixRows(matrix, gatesByStandard, issues);
756
- const projection = {
757
- schemaVersion: 1,
758
- contract: KFD_SUPPORT_PROJECTION_CONTRACT,
759
- matrix: {
760
- contract: matrix?.contract || "",
761
- root: normalizeMatrixRoot(matrix, matrixRoot),
762
- authorityPath: optionalString(matrix?.authority?.path || authorityPath),
763
- },
764
- standardPackage: {
765
- name: kfdPackageJson.name,
766
- version: kfdPackageJson.version,
767
- standardsSha256: standardsFileDigest(),
768
- },
769
- gateResults: SUPPORTED_GATE_STANDARDS.map((standard) => {
770
- const gate = gatesByStandard.get(standard);
771
- return gate
772
- ? {
773
- standard,
774
- standardRevision: gate.standardRevision,
775
- sourceSha: gate?.source?.sha || "",
776
- evidenceCut: gate.evidenceCut,
777
- status: gate.status,
778
- gateRoot: gate.gateRoot,
779
- issueCount: Array.isArray(gate.issues) ? gate.issues.length : 0,
780
- }
781
- : { standard, status: "missing", gateRoot: "", issueCount: 1 };
782
- }),
783
- rows: rows.map(projectMatrixRow),
784
- status: issues.length === 0 ? "passed" : "failed",
785
- nonClaims: [
786
- "This projection does not replace the product-owned support matrix.",
787
- "A passed Buildchain gate does not by itself activate, ship, or certify a KFD adoption.",
788
- "Candidate, unsupported, draft, and non-qualifying matrix states cannot be widened by this projection.",
789
- ],
790
- issues,
791
- };
792
- projection.projectionRoot = kfdProductGateDigest(projection);
793
- return projection;
794
- }
795
-
796
- export function validateKfdSupportProjection(projection, {
797
- expectedSourceSha = "",
798
- checkedAt = new Date().toISOString(),
799
- } = {}) {
800
- const issues = [];
801
- if (!isObject(projection) || projection.schemaVersion !== 1 || projection.contract !== KFD_SUPPORT_PROJECTION_CONTRACT) {
802
- issues.push(issue("projection-contract", "", `projection must use ${KFD_SUPPORT_PROJECTION_CONTRACT} v1`));
803
- return { valid: false, issues };
804
- }
805
- const copy = structuredClone(projection);
806
- const root = copy.projectionRoot;
807
- delete copy.projectionRoot;
808
- if (root !== kfdProductGateDigest(copy)) {
809
- issues.push(issue("projection-root", "projectionRoot", "support projection root does not match its content"));
810
- }
811
- if (projection.status !== "passed" || (projection.issues || []).length !== 0) {
812
- issues.push(issue("projection-status", "status", "release passport requires a passed support projection"));
813
- }
814
- if (
815
- projection?.standardPackage?.name !== kfdPackageJson.name ||
816
- projection?.standardPackage?.version !== kfdPackageJson.version ||
817
- projection?.standardPackage?.standardsSha256 !== standardsFileDigest()
818
- ) {
819
- issues.push(issue("projection-standard-package", "standardPackage", "support projection uses stale KFD package metadata"));
820
- }
821
- if (!new RegExp(SHA256_PATTERN).test(optionalString(projection?.matrix?.root))) {
822
- issues.push(issue("projection-matrix-root", "matrix.root", "support projection must bind the exact support matrix bytes"));
823
- }
824
- if (!optionalString(projection?.matrix?.authorityPath)) {
825
- issues.push(issue("projection-matrix-authority", "matrix.authorityPath", "support projection must retain the product-owned matrix authority path"));
826
- }
827
- const gatesByStandard = new Map();
828
- for (const [index, gate] of (projection.gateResults || []).entries()) {
829
- if (!SUPPORTED_GATE_STANDARD_SET.has(gate?.standard)) {
830
- issues.push(issue("projection-gate-standard", `gateResults[${index}].standard`, "projected gate must be kfd-4, kfd-5, or kfd-7"));
831
- continue;
832
- }
833
- if (gatesByStandard.has(gate.standard)) {
834
- issues.push(issue("projection-gate-duplicate", `gateResults[${index}].standard`, `${gate.standard} is duplicated`));
835
- }
836
- gatesByStandard.set(gate.standard, gate);
837
- if (gate.standardRevision !== standardMetadata(gate.standard).revision) {
838
- issues.push(issue("projection-gate-revision", `gateResults[${index}].standardRevision`, "projected gate revision is stale"));
839
- }
840
- if (!new RegExp(SHA256_PATTERN).test(optionalString(gate.gateRoot))) {
841
- issues.push(issue("projection-gate-root", `gateResults[${index}].gateRoot`, "projected gate must retain its gate root"));
842
- }
843
- if (expectedSourceSha && gate.sourceSha !== expectedSourceSha) {
844
- issues.push(issue("projection-source", `gateResults[${index}].sourceSha`, "gate source must match the release source"));
845
- }
846
- const checked = parseDate(checkedAt);
847
- const expires = parseDate(gate?.evidenceCut?.expiresAt);
848
- if (!Number.isFinite(expires) || (Number.isFinite(checked) && expires <= checked)) {
849
- issues.push(issue("projection-stale-gate", `gateResults[${index}].evidenceCut.expiresAt`, "projected gate evidence is stale"));
850
- }
851
- }
852
- validateMatrixRows({ rows: projection.rows }, gatesByStandard, issues);
853
- if (!Array.isArray(projection.nonClaims) || projection.nonClaims.length === 0) {
854
- issues.push(issue("projection-non-claims", "nonClaims", "support projection must preserve non-claims"));
855
- }
856
- return { valid: issues.length === 0, issues };
857
- }
858
-
859
561
  export const kfdProductGates = Object.freeze({
860
562
  evaluate: evaluateKfdProductGate,
861
- projectSupport: createKfdSupportProjection,
862
563
  validateGateResult: validateKfdProductGateResult,
863
- validateSupportProjection: validateKfdSupportProjection,
864
564
  verifyRecord: verifyKfdRecord,
865
565
  });
@@ -1,8 +1,18 @@
1
+ import path from "node:path";
1
2
  import kfdStandards from "@kungfu-tech/kfd/standards.json" with { type: "json" };
2
3
  import {
3
- RELEASE_CHECK_REPORT_CONTRACT,
4
- RELEASE_PASSPORT_CONTRACT,
5
- } from "./release-passport.js";
4
+ createKfdAdopterManifestGate,
5
+ createKfdLegacySupportMatrixProjection,
6
+ validateKfdLegacySupportMatrixProjection,
7
+ } from "./kfd-adopter-manifest.js";
8
+ import {
9
+ createKfdAdopterReleaseBinding,
10
+ installedKfdPackageArtifactRoot,
11
+ validateKfdAdopterReleaseBinding,
12
+ } from "./artifact-verification-envelope.js";
13
+
14
+ export const RELEASE_PASSPORT_CONTRACT = "kungfu-buildchain-release-passport";
15
+ export const RELEASE_CHECK_REPORT_CONTRACT = "kungfu-buildchain-release-check-report";
6
16
 
7
17
  export const RELEASE_PASSPORT_SCHEMA_ID =
8
18
  "https://buildchain.libkungfu.dev/schemas/release-passport-v1.schema.json";
@@ -100,6 +110,7 @@ export const RELEASE_PASSPORT_SCHEMA = {
100
110
  "kfd-1": OBJECT,
101
111
  "kfd-2": OBJECT,
102
112
  "kfd-3": OBJECT,
113
+ kfdAdopter: OBJECT,
103
114
  kfdSupport: OBJECT,
104
115
  },
105
116
  additionalProperties: true,
@@ -123,6 +134,7 @@ const BUILDCHAIN_AGGREGATION_FIELDS = [
123
134
  "platformArtifactManifests",
124
135
  "distTagPromotion",
125
136
  "controllerReceipts",
137
+ "kfdAdopter",
126
138
  "kfdSupport",
127
139
  "githubArtifactAttestations",
128
140
  "artifacts",
@@ -163,11 +175,12 @@ export function createReleasePassportCheckManifest({ standards = kfdStandards }
163
175
  result: "check-report.json",
164
176
  },
165
177
  kfdSupportProjection: {
166
- inputSchema: "schemas/kfd-product-gate-input-v1.schema.json",
167
- projectionSchema: "schemas/kfd-support-projection-v1.schema.json",
178
+ authorityContract: "kfd.adopter-conformance-manifest/v1",
179
+ gateContract: "kungfu-buildchain-kfd-adopter-manifest-gate",
180
+ bindingContract: "kungfu-buildchain-kfd-adopter-release-binding",
168
181
  evidence: "kfd-support.json",
169
182
  rule:
170
- "The passport mirrors one product-owned support matrix and validated product-gate results without widening any claim state.",
183
+ "The standard adopter manifest is the sole declaration authority; the legacy support matrix is an exact derived projection only.",
171
184
  },
172
185
  },
173
186
  ownership: {
@@ -199,6 +212,14 @@ export function createReleasePassportCheckManifest({ standards = kfdStandards }
199
212
  when: "kfdSupport is present",
200
213
  pointer: "evidence.kfdSupport",
201
214
  },
215
+ {
216
+ when: "kfdAdopter is present",
217
+ pointer: "evidence.kfdAdopterManifest",
218
+ },
219
+ {
220
+ when: "kfdAdopter is present",
221
+ pointer: "evidence.kfdAdopterGate",
222
+ },
202
223
  ],
203
224
  rule:
204
225
  "The normative checker resolves every declared sibling relative to the passport and fails closed on missing required evidence, digest drift, or semantic mismatch.",
@@ -264,3 +285,195 @@ export function validateReleasePassportSchema(passport) {
264
285
  issues,
265
286
  };
266
287
  }
288
+
289
+ function passportStableJson(value) {
290
+ if (Array.isArray(value)) return `[${value.map(passportStableJson).join(",")}]`;
291
+ if (value && typeof value === "object") {
292
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${passportStableJson(value[key])}`).join(",")}}`;
293
+ }
294
+ return JSON.stringify(value);
295
+ }
296
+
297
+ function passportOptional(value) {
298
+ return value === undefined || value === null ? "" : String(value);
299
+ }
300
+
301
+ export function defaultReleaseProductMechanism({ repository = "", productName = "Buildchain" } = {}) {
302
+ return {
303
+ schemaVersion: 1,
304
+ contract: "kungfu-buildchain-product-mechanism",
305
+ product: { name: productName, repository, northStar: "GitHub-native release passport protocol for binary and multi-artifact products." },
306
+ trustModel: {
307
+ executionSubstrate: "github-actions",
308
+ releaseAuthority: "protected Buildchain channel refs, exact tags, and release passport evidence",
309
+ runnerRequirement: "runner facts are recorded, but the protocol is runner-agnostic",
310
+ },
311
+ compatibility: {
312
+ promise: "release passport schemas are welded surfaces; additive fields are allowed, breaking semantic changes require a new major line",
313
+ kfd: "KFD-1",
314
+ },
315
+ };
316
+ }
317
+
318
+ export function defaultReleaseImpact({ tag = "", line = "", decision = "unknown" } = {}) {
319
+ const normalized = String(decision).toLowerCase();
320
+ const final = ["unknown", "patch", "minor", "major"].includes(normalized) ? normalized : String(decision);
321
+ return {
322
+ schemaVersion: 1,
323
+ contract: "kungfu-buildchain-impact",
324
+ release: { tag, line },
325
+ versionImpact: { final, source: "default", rationale: "No surface impact classification was supplied." },
326
+ surfaceImpacts: [],
327
+ classification: final,
328
+ breaking: final === "major",
329
+ security: false,
330
+ migrationRequired: final === "major",
331
+ summary: "No release impact summary was supplied.",
332
+ recovery: { rollback: "Use the previous exact release tag or previous floating channel ref.", block: "Fail closed if release passport verification fails." },
333
+ };
334
+ }
335
+
336
+ export function defaultReleaseAgentIndex({ tag = "", passportPath = "buildchain.release.json" } = {}) {
337
+ return {
338
+ schemaVersion: 1,
339
+ contract: "kungfu-buildchain-agent-index",
340
+ release: { tag },
341
+ entrypoints: [
342
+ { id: "release-passport", kind: "json", path: passportPath, description: "Read this first to verify release completeness, artifacts, impact, and recovery pointers." },
343
+ { id: "llms", kind: "text", path: "llms.txt", description: "Short agent-readable release instructions." },
344
+ ],
345
+ };
346
+ }
347
+
348
+ export function defaultReleaseLlmsText({ tag = "", passportPath = "buildchain.release.json" } = {}) {
349
+ return [
350
+ "# Buildchain Release Passport",
351
+ "",
352
+ `Release: ${tag || "unknown"}`,
353
+ "",
354
+ `Start with ${passportPath}. Verify artifact-evidence.json before installing binaries.`,
355
+ "If verification fails, do not install or promote this release.",
356
+ ].join("\n");
357
+ }
358
+
359
+ export function buildReleaseArtifactEvidence({ normalizedAssets = [], repository = "", tag = "", sourceSha = "", workflow = {}, kfdAdopter } = {}) {
360
+ return {
361
+ schemaVersion: 1,
362
+ contract: "kungfu-buildchain-artifact-evidence",
363
+ repository: passportOptional(repository),
364
+ release: { tag: passportOptional(tag), sourceSha: passportOptional(sourceSha) },
365
+ generatedAt: new Date().toISOString(),
366
+ runner: {
367
+ kind: passportOptional(workflow.runnerKind || workflow.runner?.kind || ""),
368
+ os: passportOptional(workflow.runnerOs || workflow.runner?.os || ""),
369
+ arch: passportOptional(workflow.runnerArch || workflow.runner?.arch || ""),
370
+ labels: Array.isArray(workflow.runnerLabels) ? workflow.runnerLabels : [],
371
+ image: passportOptional(workflow.runnerImage || workflow.runner?.image || ""),
372
+ },
373
+ workflow: {
374
+ name: passportOptional(workflow.name),
375
+ runId: passportOptional(workflow.runId),
376
+ runAttempt: passportOptional(workflow.runAttempt),
377
+ url: passportOptional(workflow.url),
378
+ },
379
+ artifacts: normalizedAssets.map((asset) => ({
380
+ name: asset.name, kind: asset.kind, platform: asset.platform, size: asset.size,
381
+ sha256: asset.sha256, url: asset.url, githubAssetId: asset.githubAssetId,
382
+ attestation: passportOptional(asset.attestation || ""),
383
+ })),
384
+ ...(kfdAdopter ? { kfdAdopter: structuredClone(kfdAdopter) } : {}),
385
+ };
386
+ }
387
+
388
+ export function prepareReleasePassportKfdSections({ kfd1, kfd2Claims, kfd3, kfdAdopter, kfdSupport, kfd1DefaultKey, createKfd2, evidencePaths = {} } = {}) {
389
+ const one = kfd1?.passportSection ? kfd1 : undefined;
390
+ const three = kfd3?.passportSection ? kfd3 : undefined;
391
+ const adopter = kfdAdopter ? structuredClone(kfdAdopter) : undefined;
392
+ const support = kfdSupport ? structuredClone(kfdSupport) : undefined;
393
+ const two = createKfd2({ explicitClaims: kfd2Claims, kfd1Section: one?.passportSection, kfd3Section: three?.passportSection });
394
+ return {
395
+ sectionEntries: [
396
+ [one?.key || kfd1DefaultKey, one?.passportSection], ["kfd-2", two],
397
+ [three?.key || "kfd-3", three?.passportSection], ["kfdAdopter", adopter], ["kfdSupport", support],
398
+ ],
399
+ evidence: {
400
+ kfd1: one ? `${one.key || kfd1DefaultKey}` : "", kfd2: two ? "kfd-2" : "", kfd3: three ? `${three.key || "kfd-3"}` : "",
401
+ kfdAdopterManifest: adopter ? evidencePaths.manifest || "kfd-adopter-manifest.json" : "",
402
+ kfdAdopterGate: adopter ? evidencePaths.gate || "kfd-adopter-manifest-gate.json" : "",
403
+ kfdSupport: support ? evidencePaths.support || "kfd-support.json" : "",
404
+ },
405
+ };
406
+ }
407
+
408
+ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], comparisonMatrix, sourceSha = "", checkedAt } = {}) {
409
+ if (!manifest) {
410
+ if (comparisonMatrix || gateResults.length > 0) {
411
+ throw new Error("KFD support and product-gate inputs require --kfd-adopter-manifest-json; --kfd-support-matrix-json is comparison-only");
412
+ }
413
+ return {};
414
+ }
415
+ const manifestGate = createKfdAdopterManifestGate({
416
+ manifest, packageArtifactRoot: installedKfdPackageArtifactRoot(), gateResults,
417
+ expectedSourceSha: sourceSha, checkedAt,
418
+ });
419
+ const legacyProjection = createKfdLegacySupportMatrixProjection({ manifest, manifestGate });
420
+ if (comparisonMatrix) {
421
+ const comparison = validateKfdLegacySupportMatrixProjection(comparisonMatrix, { manifest, manifestGate });
422
+ if (!comparison.valid) {
423
+ throw new Error(`legacy KFD support matrix drifted from the standard adopter manifest: ${JSON.stringify(comparison.issues)}`);
424
+ }
425
+ }
426
+ return {
427
+ manifest, manifestGate, legacyProjection,
428
+ binding: createKfdAdopterReleaseBinding({ manifest, manifestGate, legacyProjection, expectedSourceSha: sourceSha }),
429
+ };
430
+ }
431
+
432
+ export function validateKfdAdopterReleaseEvidence({ binding, artifactBinding, manifest, manifestGate, legacyProjection, passportLegacyProjection, expectedSourceSha = "" } = {}) {
433
+ if (!binding) {
434
+ return passportLegacyProjection
435
+ ? [{ code: "kfdSupport.authority", message: "legacy KFD support projection requires the standard adopter manifest binding" }]
436
+ : [];
437
+ }
438
+ const issues = validateKfdAdopterReleaseBinding(binding, {
439
+ manifest, manifestGate, legacyProjection, expectedSourceSha,
440
+ }).issues.map((entry) => ({ code: `kfdAdopter.${entry.path || entry.code}`, message: entry.message, details: entry }));
441
+ if (!artifactBinding || passportStableJson(artifactBinding) !== passportStableJson(binding)) {
442
+ issues.push({ code: "kfdAdopter.artifactEvidence", message: "release passport and artifact evidence must bind the same exact KFD adopter closure" });
443
+ }
444
+ if (!passportLegacyProjection || !legacyProjection
445
+ || passportStableJson(legacyProjection) !== passportStableJson(passportLegacyProjection)) {
446
+ issues.push({ code: "kfdAdopter.legacyProjection", message: "legacy support projection must exactly match the manifest-derived passport sibling" });
447
+ }
448
+ return issues;
449
+ }
450
+
451
+ async function explicitOrSibling({ location, basePath, sibling, readJson, resolveSibling, fallback }) {
452
+ if (location) return readJson(location);
453
+ return await resolveSibling(basePath, sibling) || fallback;
454
+ }
455
+
456
+ export async function resolveReleasePassportVerificationInputs({ passportLocation, locations = {}, readJson, resolveSibling } = {}) {
457
+ const passport = await readJson(passportLocation);
458
+ const basePath = /^https?:\/\//.test(passportLocation) ? passportLocation : path.resolve(passportLocation);
459
+ const resolve = (location, sibling, fallback) => explicitOrSibling({ location, basePath, sibling, readJson, resolveSibling, fallback });
460
+ const releaseEvidenceDocuments = [];
461
+ for (const reference of Array.isArray(passport.releaseEvidence) ? passport.releaseEvidence : []) {
462
+ const id = String(reference?.id || "");
463
+ const safePath = /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id) && reference?.path === `release-evidence-${id}.json`;
464
+ releaseEvidenceDocuments.push({ reference, document: safePath ? await resolveSibling(basePath, reference.path) : undefined });
465
+ }
466
+ return {
467
+ passport,
468
+ artifactEvidence: await resolve(locations.artifactEvidence, passport.evidence?.artifactEvidence, {}),
469
+ publishEvidence: await resolve(locations.publishEvidence, passport.evidence?.publishEvidence, {}),
470
+ impact: await resolve(locations.impact, passport.evidence?.impact, {}),
471
+ agentIndex: await resolve(locations.agentIndex, passport.evidence?.agentIndex, {}),
472
+ productMechanism: await resolve(locations.productMechanism, passport.product?.mechanism, {}),
473
+ kfdAgentHubEvidence: await resolve(locations.kfdAgentHubEvidence, passport.evidence?.kfdAgentHub),
474
+ kfdAdopterManifest: await resolve(locations.kfdAdopterManifest, passport.evidence?.kfdAdopterManifest),
475
+ kfdAdopterManifestGate: await resolve(locations.kfdAdopterManifestGate, passport.evidence?.kfdAdopterGate),
476
+ kfdSupportEvidence: await resolve(locations.kfdSupportEvidence, passport.evidence?.kfdSupport),
477
+ releaseEvidenceDocuments,
478
+ };
479
+ }