@kungfu-tech/buildchain 3.0.6-alpha.1 → 3.0.6-alpha.2

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 (68) hide show
  1. package/README.md +4 -4
  2. package/actions/promote-buildchain-ref/README.md +8 -0
  3. package/bin/buildchain.mjs +13 -1
  4. package/contracts/auditable-demo-scenario-v1.schema.json +52 -0
  5. package/dist/site/buildchain-contract.json +47 -27
  6. package/dist/site/buildchain-site.json +158 -42
  7. package/dist/site/capability-registry.json +3 -3
  8. package/dist/site/cli-registry.json +40 -4
  9. package/dist/site/controller-registry.json +20 -4
  10. package/dist/site/kfd-claims.json +139 -19
  11. package/dist/site/kfd-upstream-aggregate.json +1 -1
  12. package/dist/site/manual-registry.json +9 -9
  13. package/dist/site/node-api-registry.json +1161 -180
  14. package/dist/site/page-registry.json +145 -29
  15. package/dist/site/public-surface-audit.json +385 -19
  16. package/dist/site/publication-authority-registry.json +61 -1
  17. package/dist/site/publication-registry.json +4 -4
  18. package/dist/site/release-provenance.json +1 -0
  19. package/dist/site/site-manifest.json +13 -13
  20. package/dist/site/workflow-registry.json +150 -13
  21. package/docs/MAP.md +1 -0
  22. package/docs/auditable-demo.md +58 -11
  23. package/docs/aws-us-elastic-runner-burst-plane.md +23 -19
  24. package/docs/cli-reference.md +154 -0
  25. package/docs/dev-alpha-candidate-patrol.md +13 -5
  26. package/docs/dev-delivery-warrant.md +158 -0
  27. package/docs/node-api-reference.md +54 -15
  28. package/docs/publication-authority.md +11 -0
  29. package/docs/release-candidate.md +19 -2
  30. package/docs/release-governance.md +52 -0
  31. package/docs/reusable-build-surface.md +11 -1
  32. package/docs/shifu-gate-profiles.md +12 -1
  33. package/docs/versioning.md +2 -0
  34. package/package.json +2 -1
  35. package/packages/core/buildchain-publication-authority.js +3 -1
  36. package/packages/core/channel-candidate.js +2 -21
  37. package/packages/core/channel-promotion-baseline.js +199 -0
  38. package/packages/core/dev-delivery-candidate-identity.js +94 -0
  39. package/packages/core/dev-delivery-common.js +73 -0
  40. package/packages/core/dev-delivery-proof.js +252 -0
  41. package/packages/core/dev-delivery-warrant-cancellation.js +94 -0
  42. package/packages/core/dev-delivery-warrant-settlement.js +73 -0
  43. package/packages/core/dev-delivery-warrant.js +591 -0
  44. package/scripts/auditable-demo-bundle-verification.mjs +148 -0
  45. package/scripts/auditable-demo-platform.mjs +86 -50
  46. package/scripts/auditable-demo-presentation.mjs +83 -0
  47. package/scripts/auditable-demo-renditions.mjs +264 -0
  48. package/scripts/auditable-demo.mjs +24 -30
  49. package/scripts/build-contract-core.mjs +58 -3
  50. package/scripts/buildchain-cli-help.mjs +8 -0
  51. package/scripts/buildchain-patrol.mjs +9 -0
  52. package/scripts/check-inventory.mjs +1 -0
  53. package/scripts/dev-alpha-candidate-patrol.mjs +45 -48
  54. package/scripts/dev-delivery-proof.mjs +193 -0
  55. package/scripts/dev-delivery-warrant.mjs +426 -0
  56. package/scripts/dev-pr-auto-merge.mjs +488 -46
  57. package/scripts/dev-pr-delivery-warrant.mjs +209 -0
  58. package/scripts/gate-profile-core.mjs +24 -0
  59. package/scripts/generate-site-bundle.mjs +2 -2
  60. package/scripts/git-fetch-process-tree.mjs +142 -0
  61. package/scripts/lifecycle-substage-evidence.mjs +274 -0
  62. package/scripts/locked-source-checkout.mjs +6 -3
  63. package/scripts/resolve-artifact-transfer-mode.mjs +9 -0
  64. package/scripts/resolve-build-contract.mjs +7 -0
  65. package/scripts/route-offline-runners.mjs +1 -0
  66. package/scripts/run-lifecycle-core.mjs +9 -9
  67. package/scripts/shifu-gate-profile.mjs +10 -16
  68. package/scripts/site-capability-metadata.mjs +14 -0
@@ -5,6 +5,10 @@ import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import crypto from "node:crypto";
7
7
  import { decideChannelCandidate } from "../packages/core/channel-candidate.js";
8
+ import {
9
+ resolveManagedPromotionBaseline,
10
+ resolvePatrolSourceInputs,
11
+ } from "../packages/core/channel-promotion-baseline.js";
8
12
 
9
13
  export const DEV_ALPHA_CANDIDATE_STATE_SCHEMA =
10
14
  "kungfu-buildchain-dev-alpha-candidate-state/v1";
@@ -301,8 +305,7 @@ export function normalizeDevAlphaPatrolOptions(options = {}) {
301
305
  false,
302
306
  ),
303
307
  mergeMethod: autoMergeMethod(
304
- options.mergeMethod ??
305
- process.env.BUILDCHAIN_CHANNEL_PATROL_MERGE_METHOD,
308
+ options.mergeMethod ?? process.env.BUILDCHAIN_CHANNEL_PATROL_MERGE_METHOD,
306
309
  ),
307
310
  dryRun: bool(
308
311
  options.dryRun ?? process.env.BUILDCHAIN_CHANNEL_PATROL_DRY_RUN,
@@ -321,7 +324,10 @@ export function normalizeDevAlphaPatrolOptions(options = {}) {
321
324
  function latestWorkflowEvidence(runs, workflowPathValue, sourceSha) {
322
325
  const matching = runs
323
326
  .filter(
324
- (run) => run.path === workflowPathValue && run.head_sha === sourceSha,
327
+ (run) =>
328
+ run.conclusion !== "cancelled" &&
329
+ run.path === workflowPathValue &&
330
+ run.head_sha === sourceSha,
325
331
  )
326
332
  .sort((left, right) => Number(right.id) - Number(left.id));
327
333
  if (matching.length === 0)
@@ -356,7 +362,9 @@ function workflowEvidenceIsFreshAndSuccessful(run, { now, maxAgeSeconds }) {
356
362
 
357
363
  function latestRunsBySha(runs, workflowPathValue) {
358
364
  const latest = new Map();
359
- for (const run of runs.filter((row) => row.path === workflowPathValue)) {
365
+ for (const run of runs.filter(
366
+ (row) => row.path === workflowPathValue && row.conclusion !== "cancelled",
367
+ )) {
360
368
  const current = latest.get(run.head_sha);
361
369
  if (!current || Number(run.id) > Number(current.id))
362
370
  latest.set(run.head_sha, run);
@@ -620,52 +628,26 @@ export async function runDevAlphaCandidatePatrol(
620
628
  repository: options.repository,
621
629
  token: process.env.GITHUB_TOKEN,
622
630
  });
623
- const [observedSourceHeadSha, targetSha] = await Promise.all([
624
- client.resolveBranch(options.sourceBranch),
625
- client.resolveBranch(options.targetBranch),
626
- ]);
627
- const headComparison = await client.compare(targetSha, observedSourceHeadSha);
628
631
  const requiredWorkflowPaths = [
629
632
  options.devWorkflowPath,
630
633
  options.alphaWorkflowPath,
631
634
  ];
632
- let sourceSha = observedSourceHeadSha;
633
- let comparison = headComparison;
634
- let workflowEvidence = [];
635
- let skippedNewerCommitCount = 0;
636
- let qualificationError;
637
- if (
638
- headComparison.status === "ahead" &&
639
- Number(headComparison.ahead_by) > 0
640
- ) {
641
- const [sourceHistory, ...workflowRunSets] = await Promise.all([
642
- client.listBranchHistory(options.sourceBranch, targetSha),
643
- ...requiredWorkflowPaths.map((workflow) =>
644
- client.listCompletedWorkflowRuns(workflow, options.sourceBranch),
645
- ),
646
- ]);
647
- try {
648
- const selected = selectLatestQualifiedSource({
649
- sourceHistory,
650
- workflowRunsByPath: new Map(
651
- requiredWorkflowPaths.map((workflow, index) => [
652
- workflow,
653
- workflowRunSets[index],
654
- ]),
655
- ),
656
- requiredWorkflowPaths,
657
- now: options.now,
658
- maxAgeSeconds: options.maxAgeSeconds,
659
- });
660
- sourceSha = selected.sourceSha;
661
- skippedNewerCommitCount = selected.skippedNewerCommitCount;
662
- workflowEvidence = selected.workflowEvidence;
663
- if (sourceSha !== observedSourceHeadSha)
664
- comparison = await client.compare(targetSha, sourceSha);
665
- } catch (error) {
666
- qualificationError = error;
667
- }
668
- }
635
+ const {
636
+ observedSourceHeadSha,
637
+ targetSha,
638
+ headComparison,
639
+ targetBaseline,
640
+ sourceSha,
641
+ comparison,
642
+ workflowEvidence,
643
+ skippedNewerCommitCount,
644
+ qualificationError,
645
+ } = await resolvePatrolSourceInputs({
646
+ client,
647
+ options,
648
+ requiredWorkflowPaths,
649
+ selectQualifiedSource: selectLatestQualifiedSource,
650
+ });
669
651
  const decision = qualificationError
670
652
  ? blockedCandidateDecision({
671
653
  options,
@@ -682,9 +664,12 @@ export async function runDevAlphaCandidatePatrol(
682
664
  targetSha,
683
665
  comparison: { status: comparison.status, aheadBy: comparison.ahead_by },
684
666
  selection: {
685
- mode: "latest-qualified-source-ancestor",
667
+ mode: targetBaseline
668
+ ? "latest-qualified-source-after-managed-promotion"
669
+ : "latest-qualified-source-ancestor",
686
670
  observedSourceHeadSha,
687
671
  skippedNewerCommitCount,
672
+ ...(targetBaseline ? { targetBaseline } : {}),
688
673
  },
689
674
  workflowEvidence,
690
675
  requiredWorkflowPaths,
@@ -927,7 +912,12 @@ export async function runDevAlphaCandidatePatrol(
927
912
  }
928
913
  }
929
914
  }
930
- const autoMerge = await armCandidateAutoMerge(options, controllerState, pullRequest, client);
915
+ const autoMerge = await armCandidateAutoMerge(
916
+ options,
917
+ controllerState,
918
+ pullRequest,
919
+ client,
920
+ );
931
921
  return {
932
922
  schema: "kungfu-buildchain-dev-alpha-candidate-patrol/v1",
933
923
  dryRun: options.dryRun,
@@ -1015,6 +1005,13 @@ export function createGitHubChannelCandidateClient({
1015
1005
  async compare(baseSha, headSha) {
1016
1006
  return api(`/repos/${owner}/${repo}/compare/${baseSha}...${headSha}`);
1017
1007
  },
1008
+ resolveManagedPromotionBaseline: (targetSha, targetBranch) =>
1009
+ resolveManagedPromotionBaseline({
1010
+ api: (requestPath) => api(`/repos/${owner}/${repo}${requestPath}`),
1011
+ targetSha,
1012
+ targetBranch,
1013
+ parseCandidate: managedCandidateFromPullRequest,
1014
+ }),
1018
1015
  async listCompletedWorkflowRuns(workflowPathValue, sourceBranch) {
1019
1016
  const runs = [];
1020
1017
  for (let page = 1; page <= 10; page += 1) {
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { classifyDevDeliveryDelta, createIntegrationDeliveryProof, createProjectCutReplayPlan, createProjectCutReplayProof, createSourceQualificationProof, verifyIntegrationDeliveryProof, verifyProjectCutReplayProof, verifySourceQualificationProof } from "../packages/core/dev-delivery-warrant.js";
5
+
6
+ function flag(args, name, fallback = "") {
7
+ const index = args.indexOf(`--${name}`);
8
+ return index === -1 ? fallback : args[index + 1] || "";
9
+ }
10
+
11
+ function hasFlag(args, name) {
12
+ return args.includes(`--${name}`);
13
+ }
14
+
15
+ function jsonFile(file, label) {
16
+ if (!file) throw new Error(`${label} is required`);
17
+ return JSON.parse(fs.readFileSync(file, "utf8"));
18
+ }
19
+
20
+ function jsonList(value, label, { required = false } = {}) {
21
+ let parsed;
22
+ try {
23
+ parsed = JSON.parse(value || "[]");
24
+ } catch (cause) {
25
+ throw new Error(`${label} must be a JSON array: ${cause.message}`);
26
+ }
27
+ if (!Array.isArray(parsed) || (required && parsed.length === 0)) {
28
+ throw new Error(`${label} must be ${required ? "a non-empty" : "a"} JSON array`);
29
+ }
30
+ return parsed;
31
+ }
32
+
33
+ function boolean(value, fallback = false) {
34
+ if (value === undefined || value === null || value === "") return fallback;
35
+ if (typeof value === "boolean") return value;
36
+ return ["1", "true", "yes", "on"].includes(String(value).trim().toLowerCase());
37
+ }
38
+
39
+ export function devDeliveryProofCliOptions(args = [], environment = process.env) {
40
+ const [command = "", ...rest] = args;
41
+ return {
42
+ command,
43
+ repository: flag(rest, "repository", environment.GITHUB_REPOSITORY),
44
+ protectedBase: flag(rest, "branch", environment.BUILDCHAIN_DEV_DELIVERY_BRANCH || environment.GITHUB_BASE_REF),
45
+ sourceIdentityRoot: flag(rest, "source-identity-root", environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_IDENTITY_ROOT),
46
+ sourceHead: flag(rest, "source-head", environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_HEAD),
47
+ sourcePatchRoot: flag(rest, "source-patch-root", environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_PATCH_ROOT),
48
+ planRoot: flag(rest, "plan-root", environment.BUILDCHAIN_DEV_DELIVERY_PLAN_ROOT),
49
+ closureRoot: flag(rest, "closure-root", environment.BUILDCHAIN_DEV_DELIVERY_CLOSURE_ROOT),
50
+ dependencyRoot: flag(rest, "dependency-root", environment.BUILDCHAIN_DEV_DELIVERY_DEPENDENCY_ROOT),
51
+ toolchainRoot: flag(rest, "toolchain-root", environment.BUILDCHAIN_DEV_DELIVERY_TOOLCHAIN_ROOT),
52
+ affectedPaths: flag(rest, "affected-paths-json", environment.BUILDCHAIN_DEV_DELIVERY_AFFECTED_PATHS || "[]"),
53
+ shardEvidenceRoots: flag(rest, "shard-evidence-roots-json", environment.BUILDCHAIN_DEV_DELIVERY_SHARD_EVIDENCE_ROOTS || "[]"),
54
+ qualifiedAt: flag(rest, "qualified-at", environment.BUILDCHAIN_DEV_DELIVERY_QUALIFIED_AT),
55
+ sourceProofPath: flag(rest, "source-proof", environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_PROOF),
56
+ sourceProofRoot: flag(rest, "source-proof-root", environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_PROOF_ROOT),
57
+ warrantResultPath: flag(rest, "warrant-result", environment.BUILDCHAIN_DEV_DELIVERY_WARRANT_RESULT),
58
+ currentBase: flag(rest, "current-base", environment.BUILDCHAIN_DEV_DELIVERY_CURRENT_BASE),
59
+ previousBase: flag(rest, "previous-base", environment.BUILDCHAIN_DEV_DELIVERY_PREVIOUS_BASE),
60
+ replayTree: flag(rest, "replay-tree", environment.BUILDCHAIN_DEV_DELIVERY_REPLAY_TREE),
61
+ qualificationReceiptPath: flag(rest, "qualification-receipt", environment.BUILDCHAIN_DEV_DELIVERY_QUALIFICATION_RECEIPT),
62
+ mergeGroupHead: flag(rest, "merge-group-head", environment.BUILDCHAIN_DEV_DELIVERY_MERGE_GROUP_HEAD),
63
+ mergeGroupTree: flag(rest, "merge-group-tree", environment.BUILDCHAIN_DEV_DELIVERY_MERGE_GROUP_TREE),
64
+ requiredContextRoots: flag(rest, "required-context-roots-json", environment.BUILDCHAIN_DEV_DELIVERY_REQUIRED_CONTEXT_ROOTS || "[]"),
65
+ verifiedAt: flag(rest, "verified-at", environment.BUILDCHAIN_DEV_DELIVERY_VERIFIED_AT),
66
+ pullRequestNumber: flag(rest, "pull-request", environment.BUILDCHAIN_DEV_DELIVERY_PR_NUMBER),
67
+ changedPaths: flag(rest, "changed-paths-json", environment.BUILDCHAIN_DEV_DELIVERY_CHANGED_PATHS || "[]"),
68
+ graphKnown: boolean(flag(rest, "graph-known", environment.BUILDCHAIN_DEV_DELIVERY_GRAPH_KNOWN), false),
69
+ outputPath: flag(rest, "output", environment.BUILDCHAIN_DEV_DELIVERY_PROOF_OUTPUT || ".buildchain/dev-delivery/proof.json"),
70
+ json: hasFlag(rest, "json"),
71
+ };
72
+ }
73
+
74
+ function sourceProof(options) {
75
+ return createSourceQualificationProof({
76
+ repository: options.repository,
77
+ protectedBase: options.protectedBase,
78
+ sourceIdentityRoot: options.sourceIdentityRoot,
79
+ sourceHead: options.sourceHead,
80
+ sourcePatchRoot: options.sourcePatchRoot,
81
+ planRoot: options.planRoot,
82
+ closureRoot: options.closureRoot,
83
+ dependencyRoot: options.dependencyRoot,
84
+ toolchainRoot: options.toolchainRoot,
85
+ affectedPaths: jsonList(options.affectedPaths, "affected paths"),
86
+ shardEvidenceRoots: jsonList(options.shardEvidenceRoots, "shard evidence roots", { required: true }),
87
+ qualifiedAt: options.qualifiedAt,
88
+ });
89
+ }
90
+
91
+ function activeWarrant(options) {
92
+ const result = jsonFile(options.warrantResultPath, "Warrant result");
93
+ const warrant = result.warrant || result.observation?.activeWarrant;
94
+ if (result.schema !== "kungfu.buildchain.dev-delivery-command-result/v1" || !warrant) {
95
+ throw new Error("Warrant result does not contain an active Buildchain Delivery Warrant");
96
+ }
97
+ return warrant;
98
+ }
99
+
100
+ export function runDevDeliveryProofCommand(options) {
101
+ if (options.command === "source") return sourceProof(options);
102
+ if (options.command === "verify-source") {
103
+ return verifySourceQualificationProof(jsonFile(options.sourceProofPath, "source proof"));
104
+ }
105
+ if (options.command === "classify") {
106
+ return classifyDevDeliveryDelta({
107
+ proof: jsonFile(options.sourceProofPath, "source proof"),
108
+ current: {
109
+ sourceIdentityRoot: options.sourceIdentityRoot,
110
+ sourcePatchRoot: options.sourcePatchRoot,
111
+ planRoot: options.planRoot,
112
+ closureRoot: options.closureRoot,
113
+ dependencyRoot: options.dependencyRoot,
114
+ toolchainRoot: options.toolchainRoot,
115
+ graphKnown: options.graphKnown,
116
+ changedPaths: jsonList(options.changedPaths, "changed paths"),
117
+ },
118
+ });
119
+ }
120
+ if (options.command === "replay") {
121
+ return createProjectCutReplayPlan({
122
+ repository: options.repository,
123
+ protectedBase: options.protectedBase,
124
+ pullRequestNumber: options.pullRequestNumber,
125
+ sourceHead: options.sourceHead,
126
+ previousBase: options.previousBase,
127
+ currentBase: options.currentBase,
128
+ sourcePatchRoot: options.sourcePatchRoot,
129
+ replayTree: options.replayTree,
130
+ });
131
+ }
132
+ if (options.command === "replay-proof") {
133
+ return createProjectCutReplayProof({
134
+ repository: options.repository,
135
+ protectedBase: options.protectedBase,
136
+ pullRequestNumber: options.pullRequestNumber,
137
+ sourceHead: options.sourceHead,
138
+ sourcePatchRoot: options.sourcePatchRoot,
139
+ currentBase: options.currentBase,
140
+ replayTree: options.replayTree,
141
+ qualificationReceipt: jsonFile(options.qualificationReceiptPath, "Project Cut qualification receipt"),
142
+ requiredContextRoots: jsonList(options.requiredContextRoots, "required context roots", { required: true }),
143
+ verifiedAt: options.verifiedAt,
144
+ });
145
+ }
146
+ if (options.command === "verify-replay") {
147
+ return verifyProjectCutReplayProof(jsonFile(options.sourceProofPath, "Project Cut replay proof"));
148
+ }
149
+ if (options.command === "integration") {
150
+ const sourceProofRoot = options.sourceProofRoot || jsonFile(options.sourceProofPath, "source proof").proofRoot;
151
+ return createIntegrationDeliveryProof({
152
+ repository: options.repository,
153
+ protectedBase: options.protectedBase,
154
+ sourceProofRoot,
155
+ currentBase: options.currentBase,
156
+ replayTree: options.replayTree,
157
+ mergeGroupHead: options.mergeGroupHead,
158
+ mergeGroupTree: options.mergeGroupTree,
159
+ warrant: activeWarrant(options),
160
+ requiredContextRoots: jsonList(options.requiredContextRoots, "required context roots", { required: true }),
161
+ verifiedAt: options.verifiedAt,
162
+ });
163
+ }
164
+ if (options.command === "verify-integration") {
165
+ return verifyIntegrationDeliveryProof(jsonFile(options.sourceProofPath, "integration proof"));
166
+ }
167
+ throw new Error("unsupported dev delivery proof command");
168
+ }
169
+
170
+ function usage() {
171
+ return "Usage:\n buildchain dev proof <source|verify-source|classify|replay|replay-proof|verify-replay|integration|verify-integration> [options] [--output FILE] [--json]\n";
172
+ }
173
+
174
+ async function main() {
175
+ const args = process.argv.slice(2);
176
+ if (args.length === 0 || hasFlag(args, "help")) {
177
+ process.stdout.write(usage());
178
+ return;
179
+ }
180
+ const options = devDeliveryProofCliOptions(args);
181
+ const result = runDevDeliveryProofCommand(options);
182
+ fs.mkdirSync(path.dirname(options.outputPath), { recursive: true });
183
+ fs.writeFileSync(options.outputPath, `${JSON.stringify(result, null, 2)}\n`);
184
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
185
+ else process.stdout.write(`Buildchain dev delivery proof ${options.command}: ${result.proofRoot || result.reason}\n`);
186
+ }
187
+
188
+ if (import.meta.url === `file://${process.argv[1]}`) {
189
+ main().catch((error) => {
190
+ console.error(`buildchain dev proof: ${error.message}`);
191
+ process.exit(1);
192
+ });
193
+ }