@kungfu-tech/buildchain 3.0.1 → 3.0.2-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 (58) hide show
  1. package/README.md +5 -3
  2. package/actions/promote-buildchain-ref/README.md +7 -0
  3. package/bin/buildchain.mjs +173 -513
  4. package/bin/internal/cli-options.mjs +79 -0
  5. package/bin/internal/trust-release-cli.mjs +469 -0
  6. package/dist/site/agent-index.json +2 -0
  7. package/dist/site/artifact-schemas.json +5 -0
  8. package/dist/site/badge-endpoint-registry.json +18 -18
  9. package/dist/site/badges/v1/kfd-12/aligned.json +1 -1
  10. package/dist/site/badges/v1/kfd-12/declared.json +1 -1
  11. package/dist/site/badges/v1/kfd-12/downgraded.json +1 -1
  12. package/dist/site/badges/v1/kfd-12/draft.json +1 -1
  13. package/dist/site/badges/v1/kfd-12/failed.json +1 -1
  14. package/dist/site/badges/v1/kfd-12/missing.json +1 -1
  15. package/dist/site/badges/v1/kfd-12/passed.json +1 -1
  16. package/dist/site/badges/v1/kfd-12/planned.json +1 -1
  17. package/dist/site/badges/v1/kfd-13/aligned.json +1 -1
  18. package/dist/site/badges/v1/kfd-13/declared.json +1 -1
  19. package/dist/site/badges/v1/kfd-13/downgraded.json +1 -1
  20. package/dist/site/badges/v1/kfd-13/draft.json +1 -1
  21. package/dist/site/badges/v1/kfd-13/failed.json +1 -1
  22. package/dist/site/badges/v1/kfd-13/missing.json +1 -1
  23. package/dist/site/badges/v1/kfd-13/passed.json +1 -1
  24. package/dist/site/badges/v1/kfd-13/planned.json +1 -1
  25. package/dist/site/buildchain-contract.json +32 -22
  26. package/dist/site/buildchain-site.json +28 -18
  27. package/dist/site/capability-registry.json +2 -2
  28. package/dist/site/cli-registry.json +108 -0
  29. package/dist/site/controller-registry.json +10 -2
  30. package/dist/site/kfd-claims.json +136 -10
  31. package/dist/site/kfd-upstream-aggregate.json +20 -11
  32. package/dist/site/manual-registry.json +3 -3
  33. package/dist/site/node-api-registry.json +21 -8
  34. package/dist/site/page-registry.json +20 -10
  35. package/dist/site/public-surface-audit.json +114 -8
  36. package/dist/site/publication-registry.json +4 -4
  37. package/dist/site/release-passport-check-manifest.json +11 -0
  38. package/dist/site/release-provenance.json +3 -0
  39. package/dist/site/schemas/kfd-product-gate-input-v1.schema.json +164 -0
  40. package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
  41. package/dist/site/schemas/release-passport-v1.schema.json +3 -0
  42. package/dist/site/site-manifest.json +7 -7
  43. package/dist/site/workflow-registry.json +9 -3
  44. package/docs/cli.md +9 -2
  45. package/docs/kfd-support.md +43 -7
  46. package/docs/release-passport.md +15 -0
  47. package/package.json +6 -3
  48. package/packages/core/index.js +17 -0
  49. package/packages/core/kfd-product-gates.js +865 -0
  50. package/packages/core/kfd.js +16 -7
  51. package/packages/core/kfd3-surface-register.js +105 -1
  52. package/packages/core/public-surface-audit.js +6 -1
  53. package/packages/core/release-passport-contract.js +13 -0
  54. package/packages/core/release-passport.js +87 -3
  55. package/scripts/check-internal-architecture.mjs +171 -0
  56. package/scripts/check-inventory.mjs +4 -0
  57. package/scripts/generate-site-bundle.mjs +23 -0
  58. package/scripts/promotion-routing-evidence.mjs +73 -0
@@ -7,7 +7,6 @@ import { fileURLToPath } from "node:url";
7
7
  import { initBuildchainRepo } from "../scripts/init-repo.mjs";
8
8
  import { npmPublishDryRun } from "../scripts/npm-publish-dry-run.mjs";
9
9
  import { runLifecycle } from "../scripts/run-lifecycle-core.mjs";
10
- import { verifyInfraContractEvidenceBundle } from "../scripts/infra-contract-core.mjs";
11
10
  import { runReleasePropagationCli } from "../scripts/release-propagation.mjs";
12
11
  import { runReleaseGovernanceCli } from "../scripts/reconcile-release-governance.mjs";
13
12
  import { runPublicationArtifactCli } from "../scripts/publication-artifact.mjs";
@@ -18,40 +17,13 @@ import {
18
17
  createBuildchainLogger,
19
18
  defaultBuildchainLogPath,
20
19
  summarizeBuildchainLogEvents,
21
- verifyBuildchainLogEvents,
22
20
  } from "../packages/core/logging.js";
23
- import {
24
- explainReleaseLineDryRun,
25
- formatReleaseLineDryRun,
26
- } from "../packages/core/release-line-dry-run.js";
27
- import {
28
- planReleaseLineBootstrap,
29
- writeReleaseLineBootstrapVersionState,
30
- } from "../packages/core/release-line-bootstrap.js";
31
- import {
32
- collectGitHubReleasePassport,
33
- explainReleasePassport,
34
- verifyReleasePassport,
35
- } from "../packages/core/release-passport.js";
36
21
  import {
37
22
  explainKfdAgentHub,
38
23
  initKfdAgentHub,
39
24
  inspectKfdAgentHub,
40
25
  testKfdAgentHub,
41
26
  } from "../packages/core/kfd-agent-hub.js";
42
- import {
43
- createPublicationAdmission,
44
- createRunnerProvenance,
45
- verifyPublicationAdmission,
46
- } from "../packages/core/publication-authority.js";
47
- import {
48
- explainArtifactPassport,
49
- verifyArtifactPassport,
50
- } from "../packages/core/artifact-passport.js";
51
- import {
52
- projectArtifactVerificationEnvelopeToKfx,
53
- verifyArtifactVerificationEnvelope,
54
- } from "../packages/core/artifact-verification-envelope.js";
55
27
  import {
56
28
  checkBadgeBundleBlock,
57
29
  checkReadmeBadgeBlock,
@@ -102,12 +74,31 @@ import {
102
74
  queryKfd3Capabilities,
103
75
  registerKfd3Surfaces,
104
76
  } from "../packages/core/kfd3-surface-register.js";
77
+ import {
78
+ createKfdSupportProjection,
79
+ evaluateKfdProductGate,
80
+ validateKfdProductGateResult,
81
+ validateKfdSupportProjection,
82
+ } from "../packages/core/kfd-product-gates.js";
105
83
  import { createBuildchainLayoutDiscovery } from "../packages/core/buildchain-layout.js";
106
84
  import { createPortableDevCachePlan, createPortableDevCacheReceipt } from "../packages/core/portable-dev-cache.js";
107
85
  import {
108
86
  createCandidateTimeline,
109
87
  formatCandidateTimelineReport,
110
88
  } from "../packages/core/candidate-timeline.js";
89
+ import {
90
+ printJson,
91
+ readBooleanFlag,
92
+ readFlag,
93
+ readJsonInput,
94
+ readRepeatedFlag,
95
+ readRepeatedJsonInputs,
96
+ writeJsonFile,
97
+ } from "./internal/cli-options.mjs";
98
+ import {
99
+ TRUST_RELEASE_COMMANDS,
100
+ dispatchTrustReleaseCommand,
101
+ } from "./internal/trust-release-cli.mjs";
111
102
 
112
103
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
113
104
  const embeddedPackageVersion = process.env.BUILDCHAIN_EMBEDDED_PACKAGE_VERSION || "";
@@ -169,6 +160,8 @@ function usage() {
169
160
  [--kfd-3-prebuild-witness-json <json-or-path>]...
170
161
  [--kfd-3-artifact-witness-json <json-or-path>]...
171
162
  [--kfd-3-artifact-verify-cmd <command>]
163
+ [--kfd-support-matrix-json <json-or-path>]
164
+ [--kfd-product-gate-json <json-or-path>]...
172
165
  [--invariant-passport-json <json-or-path>]...
173
166
  [--invariant-passport-cmd <command>]
174
167
  [--kfd-agent-hub-evidence-json <json-or-path>]
@@ -268,6 +261,19 @@ function usage() {
268
261
  buildchain kfd 3 query [<product>] [--cwd <dir>] [--registry <path>]
269
262
  [--passport <file-or-url>] [--artifact <path>] [--json]
270
263
  buildchain kfd 4 schema [--schema <name>] [--json]
264
+ buildchain kfd 4 gate --input-json <file-or-json> [--cwd <dir>] [--output <file>] [--json]
265
+ buildchain kfd 4 verify --gate-json <file-or-json> [--expected-source-sha <sha>] [--json]
266
+ buildchain kfd 5 schema [--schema <name>] [--json]
267
+ buildchain kfd 5 gate --input-json <file-or-json> [--cwd <dir>] [--output <file>] [--json]
268
+ buildchain kfd 5 verify --gate-json <file-or-json> [--expected-source-sha <sha>] [--json]
269
+ buildchain kfd 7 schema [--schema <name>] [--json]
270
+ buildchain kfd 7 gate --input-json <file-or-json> [--cwd <dir>] [--output <file>] [--json]
271
+ buildchain kfd 7 verify --gate-json <file-or-json> [--expected-source-sha <sha>] [--json]
272
+ buildchain kfd support project --matrix-json <file-or-json> --gate-json <file-or-json>...
273
+ [--expected-source-sha <sha>] [--checked-at <date-time>]
274
+ [--output <file>] [--json]
275
+ buildchain kfd support verify --projection-json <file-or-json>
276
+ [--expected-source-sha <sha>] [--checked-at <date-time>] [--json]
271
277
  buildchain sample process-tree [--interval-ms <n>] [--label <name>]
272
278
  [--output <jsonl>] [--summary-output <json>]
273
279
  [--requested-parallelism <n>] [--json]
@@ -330,40 +336,6 @@ Examples:
330
336
  `;
331
337
  }
332
338
 
333
- function readFlag(args, name, fallback = "") {
334
- const index = args.indexOf(`--${name}`);
335
- if (index === -1) {
336
- return fallback;
337
- }
338
- return args[index + 1] || "";
339
- }
340
-
341
- function readBooleanFlag(args, name) {
342
- return args.includes(`--${name}`);
343
- }
344
-
345
- function readRepeatedFlag(args, name) {
346
- const values = [];
347
- for (let index = 0; index < args.length; index += 1) {
348
- if (args[index] === `--${name}` && args[index + 1]) {
349
- values.push(args[index + 1]);
350
- index += 1;
351
- }
352
- }
353
- return values;
354
- }
355
-
356
- function artifactEnvelopeOptions(args) {
357
- const assessmentTime = readFlag(args, "assessment-time", "");
358
- return {
359
- ...(assessmentTime ? { assessmentTime: Number(assessmentTime) } : {}),
360
- expectedEnvelopeRoot: readFlag(args, "expected-root", ""),
361
- expectedIssuer: readFlag(args, "expected-issuer", ""),
362
- expectedPublisher: readFlag(args, "expected-publisher", ""),
363
- expectedContractVersion: readFlag(args, "expected-contract", ""),
364
- };
365
- }
366
-
367
339
  function readAttributes(args) {
368
340
  const attributes = {};
369
341
  for (const value of readRepeatedFlag(args, "attribute")) {
@@ -464,38 +436,6 @@ function runScript(scriptName, args) {
464
436
  process.exitCode = result.status ?? 1;
465
437
  }
466
438
 
467
- function printJson(value) {
468
- process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
469
- }
470
-
471
- function writeJsonFile(filePath, value) {
472
- if (!filePath) {
473
- return "";
474
- }
475
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
476
- fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
477
- return filePath;
478
- }
479
-
480
- function readJsonInput(value, { cwd = process.cwd(), label = "json" } = {}) {
481
- const input = String(value || "").trim();
482
- if (!input) {
483
- throw new Error(`${label} is required`);
484
- }
485
- const filePath = path.isAbsolute(input) ? input : path.join(cwd, input);
486
- if (fs.existsSync(filePath)) {
487
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
488
- }
489
- return JSON.parse(input);
490
- }
491
-
492
- function readRepeatedJsonInputs(args, name, { cwd = process.cwd(), label = name } = {}) {
493
- return readRepeatedFlag(args, name).map((value, index) => readJsonInput(value, {
494
- cwd,
495
- label: `${label}[${index}]`,
496
- }));
497
- }
498
-
499
439
  async function runReadmeBadgesCli(args = []) {
500
440
  const [subcommand = "", surface = "", ...badgeArgs] = args;
501
441
  if (!["readme", "bundle"].includes(subcommand) || (surface && surface.startsWith("--") === false)) {
@@ -946,10 +886,136 @@ function runKfd2Cli(args = []) {
946
886
  throw new Error("usage: buildchain kfd 2 <schema|taxonomy|claims|product-claims|trust-claims|trust-assessment> ...");
947
887
  }
948
888
 
889
+ async function runKfdProductGateCli(standard, args = []) {
890
+ const [rawAction = "schema", ...rest] = args;
891
+ const action = rawAction || "schema";
892
+ const cwd = path.resolve(readFlag(rest, "cwd", process.cwd()));
893
+ const json = readBooleanFlag(rest, "json");
894
+ if (action === "schema") {
895
+ printKfdSchemaOrJson({
896
+ result: readKfdSchema({ standard, schema: readFlag(rest, "schema", "") }),
897
+ json,
898
+ });
899
+ return;
900
+ }
901
+ if (action === "gate") {
902
+ const inputValue = readFlag(rest, "input-json", "");
903
+ if (!inputValue) {
904
+ throw new Error(`buildchain kfd ${standard.slice(4)} gate requires --input-json <file-or-json>`);
905
+ }
906
+ const result = await evaluateKfdProductGate({
907
+ cwd,
908
+ input: readJsonInput(inputValue, { cwd, label: `${standard} product gate input` }),
909
+ expectedSourceSha: readFlag(rest, "expected-source-sha", ""),
910
+ checkedAt: readFlag(rest, "checked-at", "") || new Date().toISOString(),
911
+ });
912
+ const output = readFlag(rest, "output", "");
913
+ if (output) writeJsonFile(path.resolve(cwd, output), result);
914
+ if (json || !output) {
915
+ printJson(result);
916
+ } else {
917
+ process.stdout.write(`${standard} product gate: ${result.status} -> ${output}\n`);
918
+ for (const entry of result.issues) {
919
+ process.stdout.write(`- ${entry.code}: ${entry.path}: ${entry.message}\n`);
920
+ }
921
+ }
922
+ if (result.status !== "passed") process.exitCode = 1;
923
+ return;
924
+ }
925
+ if (action === "verify") {
926
+ const gateValue = readFlag(rest, "gate-json", "");
927
+ if (!gateValue) {
928
+ throw new Error(`buildchain kfd ${standard.slice(4)} verify requires --gate-json <file-or-json>`);
929
+ }
930
+ const gate = readJsonInput(gateValue, { cwd, label: `${standard} product gate result` });
931
+ const validation = validateKfdProductGateResult(gate, {
932
+ expectedSourceSha: readFlag(rest, "expected-source-sha", ""),
933
+ checkedAt: readFlag(rest, "checked-at", "") || new Date().toISOString(),
934
+ });
935
+ const result = {
936
+ schemaVersion: 1,
937
+ contract: "kungfu-buildchain-kfd-product-gate-verification",
938
+ valid: validation.valid,
939
+ passed: validation.valid && gate.status === "passed",
940
+ standard: gate.standard || standard,
941
+ gateRoot: gate.gateRoot || "",
942
+ issues: validation.issues,
943
+ };
944
+ if (json) printJson(result);
945
+ else process.stdout.write(`${standard} product gate verify: ${result.passed ? "passed" : "failed"}\n`);
946
+ if (!result.passed) process.exitCode = 1;
947
+ return;
948
+ }
949
+ throw new Error(`usage: buildchain kfd ${standard.slice(4)} <schema|gate|verify> ...`);
950
+ }
951
+
952
+ function runKfdSupportCli(args = []) {
953
+ const [action = "", ...rest] = args;
954
+ const cwd = path.resolve(readFlag(rest, "cwd", process.cwd()));
955
+ const json = readBooleanFlag(rest, "json");
956
+ const checkedAt = readFlag(rest, "checked-at", "") || new Date().toISOString();
957
+ const expectedSourceSha = readFlag(rest, "expected-source-sha", "");
958
+ if (action === "project") {
959
+ const matrixInput = readFlag(rest, "matrix-json", "");
960
+ if (!matrixInput) {
961
+ throw new Error("buildchain kfd support project requires --matrix-json <file-or-json>");
962
+ }
963
+ const matrix = readJsonInput(matrixInput, { cwd, label: "KFD support matrix" });
964
+ const matrixPath = path.resolve(cwd, matrixInput);
965
+ const matrixRoot = fs.existsSync(matrixPath)
966
+ ? `sha256:${crypto.createHash("sha256").update(fs.readFileSync(matrixPath)).digest("hex")}`
967
+ : "";
968
+ const gateResults = readRepeatedJsonInputs(rest, "gate-json", {
969
+ cwd,
970
+ label: "KFD product gate result",
971
+ });
972
+ const result = createKfdSupportProjection({
973
+ matrix,
974
+ matrixRoot,
975
+ gateResults,
976
+ expectedSourceSha,
977
+ checkedAt,
978
+ });
979
+ const output = readFlag(rest, "output", "");
980
+ if (output) writeJsonFile(path.resolve(cwd, output), result);
981
+ if (json || !output) {
982
+ printJson(result);
983
+ } else {
984
+ process.stdout.write(`KFD support projection: ${result.status} -> ${output}\n`);
985
+ for (const entry of result.issues) {
986
+ process.stdout.write(`- ${entry.code}: ${entry.path}: ${entry.message}\n`);
987
+ }
988
+ }
989
+ if (result.status !== "passed") process.exitCode = 1;
990
+ return;
991
+ }
992
+ if (action === "verify") {
993
+ const projectionInput = readFlag(rest, "projection-json", "");
994
+ if (!projectionInput) {
995
+ throw new Error("buildchain kfd support verify requires --projection-json <file-or-json>");
996
+ }
997
+ const result = validateKfdSupportProjection(
998
+ readJsonInput(projectionInput, { cwd, label: "KFD support projection" }),
999
+ { expectedSourceSha, checkedAt },
1000
+ );
1001
+ const report = {
1002
+ schemaVersion: 1,
1003
+ contract: "kungfu-buildchain-kfd-support-projection-verification",
1004
+ ok: result.valid,
1005
+ issues: result.issues,
1006
+ };
1007
+ if (json) printJson(report);
1008
+ else process.stdout.write(`KFD support projection verify: ${report.ok ? "passed" : "failed"}\n`);
1009
+ if (!report.ok) process.exitCode = 1;
1010
+ return;
1011
+ }
1012
+ throw new Error("usage: buildchain kfd support <project|verify> ...");
1013
+ }
1014
+
949
1015
  async function runKfdCli(args = []) {
950
1016
  const [subcommand = "", maybeStandardOrAction = "", ...rest] = args;
951
1017
  if (!subcommand) {
952
- throw new Error("usage: buildchain kfd <status|migrate-layout|schema|upstream|aggregate|hub|1|2|3|4> ...");
1018
+ throw new Error("usage: buildchain kfd <status|migrate-layout|schema|upstream|aggregate|hub|support|1|2|3|4|5|7> ...");
953
1019
  }
954
1020
 
955
1021
  if (subcommand === "hub") {
@@ -1038,7 +1104,7 @@ async function runKfdCli(args = []) {
1038
1104
  if (schemaCommand === "show") {
1039
1105
  const standard = maybeStandard && !maybeStandard.startsWith("--") ? maybeStandard : readFlag(effectiveArgs, "standard", "");
1040
1106
  if (!standard) {
1041
- throw new Error("usage: buildchain kfd schema show <kfd-1|kfd-2|kfd-3|kfd-4> [--schema <name>]");
1107
+ throw new Error("usage: buildchain kfd schema show <kfd-1..kfd-13> [--schema <name>]");
1042
1108
  }
1043
1109
  const result = readKfdSchema({ standard, schema: readFlag(effectiveArgs, "schema", "") });
1044
1110
  if (json) {
@@ -1117,6 +1183,11 @@ async function runKfdCli(args = []) {
1117
1183
  return;
1118
1184
  }
1119
1185
 
1186
+ if (subcommand === "support") {
1187
+ runKfdSupportCli([maybeStandardOrAction, ...rest]);
1188
+ return;
1189
+ }
1190
+
1120
1191
  const standard = normalizeKfdStandardId(subcommand);
1121
1192
  if (standard === "kfd-1") {
1122
1193
  runKfd1Cli([maybeStandardOrAction, ...rest]);
@@ -1130,17 +1201,11 @@ async function runKfdCli(args = []) {
1130
1201
  await runKfd3Cli([maybeStandardOrAction, ...rest]);
1131
1202
  return;
1132
1203
  }
1133
- if (standard === "kfd-4") {
1134
- const action = maybeStandardOrAction || "schema";
1135
- if (action === "schema") {
1136
- const schemaArgs = rest;
1137
- const json = readBooleanFlag(schemaArgs, "json");
1138
- printKfdSchemaOrJson({ result: readKfdSchema({ standard, schema: readFlag(schemaArgs, "schema", "") }), json });
1139
- return;
1140
- }
1141
- throw new Error("KFD-4 is currently schema-only in Buildchain; use: buildchain kfd 4 schema");
1204
+ if (["kfd-4", "kfd-5", "kfd-7"].includes(standard)) {
1205
+ await runKfdProductGateCli(standard, [maybeStandardOrAction, ...rest]);
1206
+ return;
1142
1207
  }
1143
- throw new Error("usage: buildchain kfd <status|migrate-layout|schema|upstream|aggregate|hub|1|2|3|4> ...");
1208
+ throw new Error("usage: buildchain kfd <status|migrate-layout|schema|upstream|aggregate|hub|support|1|2|3|4|5|7> ...");
1144
1209
  }
1145
1210
 
1146
1211
  async function runBuildFactsCli(args = []) {
@@ -1724,413 +1789,8 @@ async function main(argv = process.argv.slice(2)) {
1724
1789
  return;
1725
1790
  }
1726
1791
 
1727
- if (command === "release") {
1728
- if (args[0] === "line" && args[1] === "open") {
1729
- const lineArgs = args.slice(2);
1730
- const options = {
1731
- cwd: readFlag(lineArgs, "cwd", process.cwd()),
1732
- major: readFlag(lineArgs, "major", ""),
1733
- minor: readFlag(lineArgs, "minor", ""),
1734
- sourceRef: readFlag(lineArgs, "source-ref", ""),
1735
- initialVersion: readFlag(lineArgs, "initial-version", ""),
1736
- };
1737
- const result = readBooleanFlag(lineArgs, "write")
1738
- ? writeReleaseLineBootstrapVersionState({
1739
- ...options,
1740
- runVersionStateLifecycle: !readBooleanFlag(lineArgs, "skip-version-state-lifecycle"),
1741
- generatedAt: readFlag(lineArgs, "generated-at", ""),
1742
- })
1743
- : planReleaseLineBootstrap({
1744
- ...options,
1745
- requiredStatusCheck: readFlag(lineArgs, "required-status-check", "check"),
1746
- setDefault: !readBooleanFlag(lineArgs, "no-set-default"),
1747
- createAlphaPr: !readBooleanFlag(lineArgs, "no-alpha-pr"),
1748
- approvalCount: Number(readFlag(lineArgs, "approval-count", "1")),
1749
- bootstrapBranch: readFlag(lineArgs, "bootstrap-branch", ""),
1750
- });
1751
- if (readBooleanFlag(lineArgs, "json")) {
1752
- printJson(result);
1753
- } else {
1754
- process.stdout.write(`Buildchain release line bootstrap ${result.line}\n`);
1755
- process.stdout.write(`- source: ${result.source.ref}${result.source.sha ? ` (${result.source.sha})` : ""}\n`);
1756
- process.stdout.write(`- initial version: ${result.initialVersion}\n`);
1757
- process.stdout.write(`- dev: ${result.refs.dev}\n`);
1758
- process.stdout.write(`- alpha: ${result.refs.alpha}\n`);
1759
- process.stdout.write(`- release: ${result.refs.release}\n`);
1760
- process.stdout.write(`- version files: ${result.versionState.files.join(", ") || "none"}\n`);
1761
- if (result.changedFiles) {
1762
- process.stdout.write(`- changed files: ${result.changedFiles.join(", ") || "none"}\n`);
1763
- }
1764
- process.stdout.write(result.dryRun ? "No refs, branches, PRs, or files were modified.\n" : "Version-state files were updated in the working tree.\n");
1765
- }
1766
- return;
1767
- }
1768
- const explainMode = args[0] === "dry-run" || args[0] === "explain";
1769
- const releaseArgs = explainMode ? args.slice(1) : args;
1770
- if (explainMode || readBooleanFlag(args, "dry-run")) {
1771
- const plan = explainReleaseLineDryRun({
1772
- cwd: readFlag(releaseArgs, "cwd", process.cwd()),
1773
- targetRef: readFlag(releaseArgs, "target-ref", ""),
1774
- sourceRef: readFlag(releaseArgs, "source-ref", ""),
1775
- sha: readFlag(releaseArgs, "sha", ""),
1776
- tags: readFlag(releaseArgs, "tags", ""),
1777
- publishTransaction: readBooleanFlag(releaseArgs, "publish-transaction"),
1778
- publishCommand: readFlag(releaseArgs, "publish-command", ""),
1779
- });
1780
- if (readBooleanFlag(releaseArgs, "json")) {
1781
- printJson(plan);
1782
- } else {
1783
- process.stdout.write(formatReleaseLineDryRun(plan));
1784
- }
1785
- return;
1786
- }
1787
- runScript("release-transaction.mjs", args);
1788
- return;
1789
- }
1790
-
1791
- if (command === "transaction") {
1792
- const [subcommand = "inspect", ...transactionArgs] = args;
1793
- if (subcommand !== "inspect") {
1794
- throw new Error("usage: buildchain transaction inspect ...");
1795
- }
1796
- runScript("release-transaction.mjs", ["inspect", ...transactionArgs]);
1797
- return;
1798
- }
1799
-
1800
- if (command === "create") {
1801
- const [subcommand = "", ...createArgs] = args;
1802
- const inputValue = readFlag(createArgs, "input-json", "");
1803
- if (!inputValue || !["publication-admission", "runner-provenance"].includes(subcommand)) {
1804
- throw new Error("usage: buildchain create <publication-admission|runner-provenance> --input-json <file-or-json> [--output <file>]");
1805
- }
1806
- const input = readJsonInput(inputValue, { label: "input-json" });
1807
- const value = subcommand === "publication-admission"
1808
- ? createPublicationAdmission(input)
1809
- : createRunnerProvenance(input);
1810
- const output = readFlag(createArgs, "output", "");
1811
- if (output) writeJsonFile(path.resolve(output), value);
1812
- if (!output || readBooleanFlag(createArgs, "json")) printJson(value);
1813
- else process.stdout.write(`${subcommand}: ${output}\n`);
1814
- return;
1815
- }
1816
-
1817
- if (command === "collect") {
1818
- const [subcommand = "", ...collectArgs] = args;
1819
- if (subcommand !== "github-release") {
1820
- throw new Error("usage: buildchain collect github-release --tag <tag>");
1821
- }
1822
- const workflow = {
1823
- name: process.env.GITHUB_WORKFLOW || "",
1824
- runId: process.env.GITHUB_RUN_ID || "",
1825
- runAttempt: process.env.GITHUB_RUN_ATTEMPT || "",
1826
- url: process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY && process.env.GITHUB_RUN_ID
1827
- ? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`
1828
- : "",
1829
- runnerKind: process.env.BUILDCHAIN_RUNNER_KIND || "github-hosted",
1830
- runnerOs: process.env.RUNNER_OS || process.platform,
1831
- runnerArch: process.env.RUNNER_ARCH || process.arch,
1832
- runnerImage: process.env.ImageOS || "",
1833
- };
1834
- const result = collectGitHubReleasePassport({
1835
- cwd: readFlag(collectArgs, "cwd", process.cwd()),
1836
- tag: readFlag(collectArgs, "tag", ""),
1837
- repository: readFlag(collectArgs, "repository", process.env.GITHUB_REPOSITORY || ""),
1838
- sourceSha: readFlag(collectArgs, "source-sha", process.env.GITHUB_SHA || ""),
1839
- line: readFlag(collectArgs, "line", ""),
1840
- outputDir: readFlag(collectArgs, "output-dir", ".buildchain/release-passport"),
1841
- assetsDir: readFlag(collectArgs, "assets-dir", ""),
1842
- assetsJson: readFlag(collectArgs, "assets-json", ""),
1843
- releaseJson: readFlag(collectArgs, "release-json", ""),
1844
- productName: readFlag(collectArgs, "product-name", "Buildchain"),
1845
- packageName: readFlag(collectArgs, "package-name", "@kungfu-tech/buildchain"),
1846
- packageVersion: readFlag(collectArgs, "package-version", packageVersion()),
1847
- packageSetJson: readFlag(collectArgs, "package-set-json", ""),
1848
- publishEvidenceJson: readFlag(collectArgs, "publish-evidence-json", ""),
1849
- trustedPublishingJson: readFlag(collectArgs, "trusted-publishing-json", ""),
1850
- transactionJson: readFlag(collectArgs, "transaction-json", ""),
1851
- anchorManifestJson: readFlag(collectArgs, "anchor-manifest-json", ""),
1852
- impactJson: readFlag(collectArgs, "impact-json", ""),
1853
- buildSummaryJson: readFlag(collectArgs, "build-summary-json", ""),
1854
- buildFactsJsons: readRepeatedFlag(collectArgs, "build-facts-json"),
1855
- platformManifestJsons: readRepeatedFlag(collectArgs, "platform-manifest-json"),
1856
- distTagEvidenceJson: readFlag(collectArgs, "dist-tag-evidence-json", ""),
1857
- kfd1WitnessJsons: readRepeatedFlag(collectArgs, "kfd-1-witness-json"),
1858
- kfd2ClaimJsons: readRepeatedFlag(collectArgs, "kfd-2-claim-json"),
1859
- kfd3PrebuildWitnessJsons: readRepeatedFlag(collectArgs, "kfd-3-prebuild-witness-json"),
1860
- kfd3ArtifactWitnessJsons: readRepeatedFlag(collectArgs, "kfd-3-artifact-witness-json"),
1861
- kfd3ArtifactVerifyCommand: readFlag(collectArgs, "kfd-3-artifact-verify-cmd", ""),
1862
- invariantPassportJsons: readRepeatedFlag(collectArgs, "invariant-passport-json"),
1863
- invariantPassportCommand: readFlag(collectArgs, "invariant-passport-cmd", ""),
1864
- kfdAgentHubEvidenceJson: readFlag(collectArgs, "kfd-agent-hub-evidence-json", ""),
1865
- basePassportJson: readFlag(collectArgs, "base-passport-json", ""),
1866
- requireBaseKfd: readBooleanFlag(collectArgs, "require-base-kfd"),
1867
- releaseJsonExtra: readFlag(collectArgs, "release-extra-json", ""),
1868
- publishJson: readFlag(collectArgs, "publish-json", ""),
1869
- workflow,
1870
- });
1871
- if (readBooleanFlag(collectArgs, "json")) {
1872
- printJson(result);
1873
- } else {
1874
- process.stdout.write(`release passport collected: ${path.relative(process.cwd(), result.outputDir)}\n`);
1875
- process.stdout.write(`artifacts: ${result.artifactEvidence.artifacts.length}\n`);
1876
- }
1877
- return;
1878
- }
1879
-
1880
- if (command === "project") {
1881
- const [subcommand = "", location = "", ...projectArgs] = args;
1882
- if (subcommand !== "kfx-admission" || !location) {
1883
- throw new Error("usage: buildchain project kfx-admission <file-or-json>");
1884
- }
1885
- const projection = projectArtifactVerificationEnvelopeToKfx({
1886
- envelope: readJsonInput(location, { label: "artifact verification envelope" }),
1887
- ...artifactEnvelopeOptions(projectArgs),
1888
- });
1889
- if (readBooleanFlag(projectArgs, "json")) {
1890
- printJson(projection);
1891
- } else {
1892
- process.stdout.write(`KFX admission envelope: ${projection.envelopeRoot}\n`);
1893
- }
1894
- return;
1895
- }
1896
-
1897
- if (command === "verify") {
1898
- const [subcommand = "", location = "", ...verifyArgs] = args;
1899
- if (subcommand === "publication-admission") {
1900
- if (!location) {
1901
- throw new Error("usage: buildchain verify publication-admission <file-or-json> --registry-json <file-or-json> --runner-json <file-or-json> --control-plane-audit-json <file-or-json> --publication-evidence-json <file-or-json>");
1902
- }
1903
- const requiredInput = (name) => {
1904
- const value = readFlag(verifyArgs, name, "");
1905
- if (!value) throw new Error(`buildchain verify publication-admission requires --${name} <file-or-json>`);
1906
- return readJsonInput(value, { label: name });
1907
- };
1908
- const expectedInput = readFlag(verifyArgs, "expected-json", "");
1909
- const capability = verifyPublicationAdmission({
1910
- admission: readJsonInput(location, { label: "publication admission" }),
1911
- registry: requiredInput("registry-json"),
1912
- runnerProvenance: requiredInput("runner-json"),
1913
- controlPlaneAudit: requiredInput("control-plane-audit-json"),
1914
- publicationEvidence: requiredInput("publication-evidence-json"),
1915
- expected: expectedInput ? readJsonInput(expectedInput, { label: "expected-json" }) : {},
1916
- usedNonces: readRepeatedFlag(verifyArgs, "used-nonce"),
1917
- });
1918
- if (readBooleanFlag(verifyArgs, "json")) {
1919
- printJson(capability);
1920
- } else {
1921
- process.stdout.write(`publication admission: ${capability.decision}\n`);
1922
- process.stdout.write(`capability digest: ${capability.capabilityDigest}\n`);
1923
- process.stdout.write(`expires at: ${capability.expiresAt}\n`);
1924
- }
1925
- return;
1926
- }
1927
- if (subcommand === "artifact") {
1928
- if (!location) {
1929
- throw new Error("usage: buildchain verify artifact <subject>");
1930
- }
1931
- const report = await verifyArtifactPassport({
1932
- subject: location,
1933
- cwd: process.cwd(),
1934
- passportLocation: readFlag(verifyArgs, "passport", ""),
1935
- locatorConfig: readFlag(verifyArgs, "locator-config", ""),
1936
- repository: readFlag(verifyArgs, "repository", ""),
1937
- tag: readFlag(verifyArgs, "tag", ""),
1938
- githubReleaseBaseUrl: readFlag(verifyArgs, "github-release-base-url", ""),
1939
- subjectDigest: readFlag(verifyArgs, "subject-digest", ""),
1940
- subjectKind: readFlag(verifyArgs, "subject-kind", ""),
1941
- npmRegistryBaseUrl: readFlag(verifyArgs, "npm-registry", ""),
1942
- });
1943
- if (readBooleanFlag(verifyArgs, "json")) {
1944
- printJson(report);
1945
- } else {
1946
- process.stdout.write(`artifact: ${report.outcome}\n`);
1947
- process.stdout.write(`subject: ${report.subject?.name || location}\n`);
1948
- process.stdout.write(`passport: ${report.passport?.location || report.discovery?.passportLocation || "unresolved"}\n`);
1949
- for (const entry of report.issues) {
1950
- process.stdout.write(`- ${entry.level}: ${entry.code}: ${entry.message}\n`);
1951
- }
1952
- }
1953
- process.exitCode = report.ok ? 0 : 1;
1954
- return;
1955
- }
1956
- if (subcommand === "artifact-envelope") {
1957
- if (!location) {
1958
- throw new Error("usage: buildchain verify artifact-envelope <file-or-json>");
1959
- }
1960
- const report = verifyArtifactVerificationEnvelope({
1961
- envelope: readJsonInput(location, { label: "artifact verification envelope" }),
1962
- ...artifactEnvelopeOptions(verifyArgs),
1963
- });
1964
- if (readBooleanFlag(verifyArgs, "json")) {
1965
- printJson(report);
1966
- } else {
1967
- process.stdout.write(`artifact verification envelope: ${report.outcome}\n`);
1968
- process.stdout.write(`root: ${report.envelopeRoot || "unresolved"}\n`);
1969
- for (const entry of report.issues) {
1970
- process.stdout.write(`- ${entry.level}: ${entry.code}: ${entry.message}\n`);
1971
- }
1972
- }
1973
- process.exitCode = report.ok ? 0 : 1;
1974
- return;
1975
- }
1976
- if (subcommand === "observability-log") {
1977
- if (!location) {
1978
- throw new Error("usage: buildchain verify observability-log <jsonl>");
1979
- }
1980
- const report = verifyBuildchainLogEvents({
1981
- path: location,
1982
- minEvents: Number(readFlag(verifyArgs, "min-events", "1")),
1983
- allowErrors: readBooleanFlag(verifyArgs, "allow-errors"),
1984
- requirePhases: readRepeatedFlag(verifyArgs, "require-phase"),
1985
- requireComponents: readRepeatedFlag(verifyArgs, "require-component"),
1986
- requireEvents: readRepeatedFlag(verifyArgs, "require-event"),
1987
- });
1988
- if (readBooleanFlag(verifyArgs, "json")) {
1989
- printJson(report);
1990
- } else {
1991
- process.stdout.write(`observability log: ${report.ok ? "ok" : "failed"}\n`);
1992
- process.stdout.write(`events: ${report.summary.eventCount}\n`);
1993
- for (const entry of report.issues) {
1994
- process.stdout.write(`- ${entry.level}: ${entry.code}: ${entry.message}\n`);
1995
- }
1996
- }
1997
- process.exitCode = report.ok ? 0 : 1;
1998
- return;
1999
- }
2000
- if (subcommand === "infra-contract-evidence-bundle") {
2001
- if (!location) {
2002
- throw new Error("usage: buildchain verify infra-contract-evidence-bundle <file>");
2003
- }
2004
- const bundle = JSON.parse(fs.readFileSync(path.resolve(location), "utf8"));
2005
- const report = verifyInfraContractEvidenceBundle(bundle);
2006
- if (readBooleanFlag(verifyArgs, "json")) {
2007
- printJson(report);
2008
- } else {
2009
- process.stdout.write(`infra contract evidence bundle: ${report.ok ? "ok" : "failed"}\n`);
2010
- process.stdout.write(`artifact: ${report.artifactHash || "unknown"}\n`);
2011
- for (const entry of report.issues) {
2012
- process.stdout.write(`- ${entry.level}: ${entry.code}: ${entry.message}\n`);
2013
- }
2014
- }
2015
- process.exitCode = report.ok ? 0 : 1;
2016
- return;
2017
- }
2018
- if (subcommand !== "release-passport" || !location) {
2019
- throw new Error("usage: buildchain verify release-passport <file-or-url>");
2020
- }
2021
- const report = await verifyReleasePassport({ passportLocation: location });
2022
- if (readBooleanFlag(verifyArgs, "json")) {
2023
- printJson(report);
2024
- } else {
2025
- process.stdout.write(`release passport: ${report.ok ? "ok" : "failed"}\n`);
2026
- process.stdout.write(`artifacts: ${report.completeness.artifactCount}\n`);
2027
- for (const entry of report.issues) {
2028
- process.stdout.write(`- ${entry.level}: ${entry.code}: ${entry.message}\n`);
2029
- }
2030
- }
2031
- process.exitCode = report.ok ? 0 : 1;
2032
- return;
2033
- }
2034
-
2035
- if (command === "audit") {
2036
- const [subcommand = "", ...auditArgs] = args;
2037
- if (subcommand === "publication-control-plane") {
2038
- runScript("audit-publication-control-plane.mjs", auditArgs);
2039
- return;
2040
- }
2041
- if (subcommand === "github-governance") {
2042
- runScript("audit-github-governance.mjs", auditArgs);
2043
- return;
2044
- }
2045
- throw new Error("usage: buildchain audit <publication-control-plane|github-governance> ...");
2046
- }
2047
-
2048
- if (command === "explain") {
2049
- const [subcommand = "", ...explainArgs] = args;
2050
- if (subcommand === "artifact") {
2051
- const subject = explainArgs[0] || "";
2052
- if (!subject) {
2053
- throw new Error("usage: buildchain explain artifact <subject>");
2054
- }
2055
- const explanation = await explainArtifactPassport({
2056
- subject,
2057
- cwd: process.cwd(),
2058
- passportLocation: readFlag(explainArgs, "passport", ""),
2059
- locatorConfig: readFlag(explainArgs, "locator-config", ""),
2060
- repository: readFlag(explainArgs, "repository", ""),
2061
- tag: readFlag(explainArgs, "tag", ""),
2062
- githubReleaseBaseUrl: readFlag(explainArgs, "github-release-base-url", ""),
2063
- subjectDigest: readFlag(explainArgs, "subject-digest", ""),
2064
- subjectKind: readFlag(explainArgs, "subject-kind", ""),
2065
- npmRegistryBaseUrl: readFlag(explainArgs, "npm-registry", ""),
2066
- forAudience: readFlag(explainArgs, "for", "human"),
2067
- });
2068
- if (readBooleanFlag(explainArgs, "json")) {
2069
- printJson(explanation);
2070
- } else {
2071
- process.stdout.write(`artifact: ${explanation.subject?.name || subject}\n`);
2072
- process.stdout.write(`trust: ${explanation.trust}\n`);
2073
- process.stdout.write(`next action: ${explanation.nextAction}\n`);
2074
- }
2075
- process.exitCode = explanation.trust === "pass" ? 0 : 1;
2076
- return;
2077
- }
2078
- if (subcommand !== "release") {
2079
- throw new Error("usage: buildchain explain release --passport <file-or-url>");
2080
- }
2081
- const passport = readFlag(explainArgs, "passport", "");
2082
- if (!passport) {
2083
- throw new Error("buildchain explain release requires --passport <file-or-url>");
2084
- }
2085
- const explanation = await explainReleasePassport({
2086
- passportLocation: passport,
2087
- forAudience: readFlag(explainArgs, "for", "human"),
2088
- });
2089
- if (readBooleanFlag(explainArgs, "json")) {
2090
- printJson(explanation);
2091
- } else {
2092
- process.stdout.write(`release: ${explanation.release?.tag || "unknown"}\n`);
2093
- process.stdout.write(`trust: ${explanation.trust}\n`);
2094
- process.stdout.write(`next action: ${explanation.nextAction}\n`);
2095
- }
2096
- return;
2097
- }
2098
-
2099
- if (command === "inspect") {
2100
- const [subcommand = "", ...inspectArgs] = args;
2101
- if (subcommand === "artifact") {
2102
- const subject = inspectArgs[0] || "";
2103
- if (!subject) {
2104
- throw new Error("usage: buildchain inspect artifact <subject>");
2105
- }
2106
- const report = await verifyArtifactPassport({
2107
- subject,
2108
- cwd: process.cwd(),
2109
- passportLocation: readFlag(inspectArgs, "passport", ""),
2110
- locatorConfig: readFlag(inspectArgs, "locator-config", ""),
2111
- repository: readFlag(inspectArgs, "repository", ""),
2112
- tag: readFlag(inspectArgs, "tag", ""),
2113
- githubReleaseBaseUrl: readFlag(inspectArgs, "github-release-base-url", ""),
2114
- subjectDigest: readFlag(inspectArgs, "subject-digest", ""),
2115
- subjectKind: readFlag(inspectArgs, "subject-kind", ""),
2116
- npmRegistryBaseUrl: readFlag(inspectArgs, "npm-registry", ""),
2117
- });
2118
- printJson(report);
2119
- process.exitCode = report.ok ? 0 : 1;
2120
- return;
2121
- }
2122
- if (subcommand !== "release") {
2123
- throw new Error("usage: buildchain inspect release --passport <file-or-url>");
2124
- }
2125
- const passport = readFlag(inspectArgs, "passport", "");
2126
- if (!passport) {
2127
- throw new Error("buildchain inspect release requires --passport <file-or-url>");
2128
- }
2129
- const explanation = await explainReleasePassport({
2130
- passportLocation: passport,
2131
- forAudience: readFlag(inspectArgs, "for", "human"),
2132
- });
2133
- printJson(explanation);
1792
+ if (TRUST_RELEASE_COMMANDS.has(command)) {
1793
+ await dispatchTrustReleaseCommand({ command, args, runScript, packageVersion });
2134
1794
  return;
2135
1795
  }
2136
1796