@kungfu-tech/buildchain 3.0.6-alpha.0 → 3.0.6-alpha.10
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/README.md +4 -4
- package/actions/promote-buildchain-ref/README.md +13 -1
- package/bin/buildchain.mjs +13 -1
- package/contracts/auditable-demo-scenario-v1.schema.json +52 -0
- package/contracts/release-candidate-recovery-v1.schema.json +104 -0
- package/dist/site/buildchain-contract.json +134 -34
- package/dist/site/buildchain-site.json +178 -47
- package/dist/site/capability-registry.json +5 -5
- package/dist/site/cli-registry.json +40 -4
- package/dist/site/controller-registry.json +60 -4
- package/dist/site/kfd-claims.json +190 -20
- package/dist/site/kfd-upstream-aggregate.json +9 -9
- package/dist/site/manual-registry.json +10 -10
- package/dist/site/node-api-registry.json +1295 -80
- package/dist/site/page-registry.json +164 -33
- package/dist/site/public-surface-audit.json +428 -21
- package/dist/site/publication-authority-registry.json +66 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +2 -0
- package/dist/site/site-manifest.json +14 -14
- package/dist/site/workflow-registry.json +203 -15
- package/docs/MAP.md +2 -0
- package/docs/auditable-demo.md +58 -11
- package/docs/aws-us-elastic-runner-burst-plane.md +114 -80
- package/docs/cli-reference.md +154 -0
- package/docs/dev-alpha-candidate-patrol.md +13 -5
- package/docs/dev-delivery-warrant.md +158 -0
- package/docs/node-api-reference.md +105 -44
- package/docs/publication-authority.md +11 -0
- package/docs/publish-transaction.md +10 -1
- package/docs/release-candidate.md +140 -12
- package/docs/release-governance.md +66 -1
- package/docs/reusable-build-surface.md +11 -1
- package/docs/shifu-gate-profiles.md +12 -1
- package/docs/versioning.md +2 -0
- package/package.json +5 -2
- package/packages/core/buildchain-contract.js +30 -2
- package/packages/core/buildchain-publication-authority.js +3 -1
- package/packages/core/channel-candidate.js +2 -21
- package/packages/core/channel-promotion-baseline.js +199 -0
- package/packages/core/dev-delivery-candidate-identity.js +94 -0
- package/packages/core/dev-delivery-common.js +73 -0
- package/packages/core/dev-delivery-proof.js +252 -0
- package/packages/core/dev-delivery-warrant-cancellation.js +94 -0
- package/packages/core/dev-delivery-warrant-settlement.js +73 -0
- package/packages/core/dev-delivery-warrant.js +591 -0
- package/packages/core/index.js +7 -0
- package/packages/core/publication-sealed-bundle.js +10 -1
- package/packages/core/release-candidate-recovery.js +539 -0
- package/scripts/audit-publication-control-plane.mjs +12 -4
- package/scripts/auditable-demo-bundle-verification.mjs +148 -0
- package/scripts/auditable-demo-platform.mjs +86 -50
- package/scripts/auditable-demo-presentation.mjs +83 -0
- package/scripts/auditable-demo-renditions.mjs +264 -0
- package/scripts/auditable-demo.mjs +24 -30
- package/scripts/aws-windows-jit-campaign-core.mjs +7 -8
- package/scripts/aws-windows-jit-controller.mjs +1 -0
- package/scripts/aws-windows-jit-core.mjs +1 -1
- package/scripts/build-contract-core.mjs +58 -3
- package/scripts/buildchain-cli-help.mjs +8 -0
- package/scripts/buildchain-patrol.mjs +9 -0
- package/scripts/check-inventory.mjs +25 -3
- package/scripts/dev-alpha-candidate-patrol.mjs +45 -48
- package/scripts/dev-delivery-proof.mjs +193 -0
- package/scripts/dev-delivery-warrant.mjs +426 -0
- package/scripts/dev-pr-auto-merge.mjs +497 -55
- package/scripts/dev-pr-delivery-warrant.mjs +209 -0
- package/scripts/dispatch-artifact-signing-authority.mjs +2 -4
- package/scripts/gate-profile-core.mjs +24 -0
- package/scripts/generate-channel-promotion-workflow.mjs +30 -14
- package/scripts/generate-site-bundle.mjs +2 -2
- package/scripts/git-fetch-process-tree.mjs +142 -0
- package/scripts/lifecycle-substage-evidence.mjs +274 -0
- package/scripts/locked-source-checkout.mjs +6 -3
- package/scripts/publication-candidate-sealer.mjs +104 -0
- package/scripts/release-candidate-resolver.mjs +91 -5
- package/scripts/resolve-artifact-transfer-mode.mjs +9 -0
- package/scripts/resolve-build-contract.mjs +7 -0
- package/scripts/resume-from-candidate-run.mjs +598 -0
- package/scripts/route-offline-runners.mjs +1 -0
- package/scripts/run-lifecycle-core.mjs +9 -9
- package/scripts/shifu-gate-profile.mjs +10 -16
- package/scripts/site-capability-metadata.mjs +15 -0
|
@@ -74,6 +74,7 @@ const requiredPaths = [
|
|
|
74
74
|
"docs/shifu-gate-profiles.md",
|
|
75
75
|
"docs/auditable-demo.md",
|
|
76
76
|
"contracts/auditable-demo-scenario-v1.schema.json",
|
|
77
|
+
"contracts/release-candidate-recovery-v1.schema.json",
|
|
77
78
|
"contracts/auditable-demo-media-profiles-v1.json",
|
|
78
79
|
"contracts/evidence/auditable-demo-web-delivery-v1.json",
|
|
79
80
|
"contracts/evidence/auditable-demo-responsive-web-delivery-v1.json",
|
|
@@ -117,6 +118,7 @@ const requiredPaths = [
|
|
|
117
118
|
"scripts/publication-commit-evidence.mjs",
|
|
118
119
|
"scripts/publication-reproducibility.mjs",
|
|
119
120
|
"scripts/release-candidate-resolver.mjs",
|
|
121
|
+
"scripts/resume-from-candidate-run.mjs",
|
|
120
122
|
"scripts/buildchain-patrol.mjs",
|
|
121
123
|
"scripts/observed-evidence.mjs",
|
|
122
124
|
"scripts/workflow-friction-report.mjs",
|
|
@@ -134,9 +136,11 @@ const requiredPaths = [
|
|
|
134
136
|
".github/actionlint.yaml",
|
|
135
137
|
".github/workflows/self-hosted-runner-smoke.yml",
|
|
136
138
|
".github/workflows/buildchain-ref-promotion.yml",
|
|
139
|
+
".github/workflows/buildchain-candidate-recovery-dogfood-failure.yml",
|
|
137
140
|
".github/workflows/release-line-bootstrap.yml",
|
|
138
141
|
".github/workflows/release-governance-reconcile.yml",
|
|
139
142
|
".github/workflows/dev-pr-auto-merge.yml",
|
|
143
|
+
".github/workflows/buildchain-dev-delivery.yml",
|
|
140
144
|
".github/workflows/buildchain-patrol.yml",
|
|
141
145
|
".github/workflows/patrol-daily.yml",
|
|
142
146
|
".github/workflows/patrol-weekly.yml",
|
|
@@ -272,16 +276,25 @@ if (channelPromotionWorkflow !== generateChannelPromotionWorkflow(advancedPromot
|
|
|
272
276
|
}
|
|
273
277
|
for (const requiredSnippet of [
|
|
274
278
|
"buildchain-channel:",
|
|
275
|
-
|
|
279
|
+
`/${promotionShellRouting.alpha.workflowPath}@${promotionShellRouting.alpha.callRef}`,
|
|
276
280
|
`/${promotionShellRouting.stable.workflowPath}@${promotionShellRouting.stable.callRef}`,
|
|
277
281
|
`STABLE_SHELL_REF: v${selfDogfoodMajor}`,
|
|
278
282
|
"promotion-contract-lock-digest:",
|
|
279
283
|
"authorize-promotion-runtime-override.cjs",
|
|
284
|
+
"BUILDCHAIN_ROUTER_REPOSITORY: ${{ inputs.buildchain-repository }}",
|
|
285
|
+
"BUILDCHAIN_RESUME_RUNTIME_SHA: ${{ inputs.resume-buildchain-runtime-sha }}",
|
|
286
|
+
"git ls-remote",
|
|
287
|
+
"Recovery router ref does not match resume-buildchain-runtime-sha",
|
|
280
288
|
]) {
|
|
281
289
|
if (!channelPromotionWorkflow.includes(requiredSnippet)) {
|
|
282
290
|
throw new Error(`channel promotion workflow missing routing contract: ${requiredSnippet}`);
|
|
283
291
|
}
|
|
284
292
|
}
|
|
293
|
+
for (const forbiddenSnippet of ["job.workflow_repository", "job.workflow_sha"]) {
|
|
294
|
+
if (channelPromotionWorkflow.includes(forbiddenSnippet)) {
|
|
295
|
+
throw new Error(`channel promotion workflow uses unsupported GitHub context: ${forbiddenSnippet}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
285
298
|
const promotionOverrideAuthorization = fs.readFileSync(
|
|
286
299
|
path.join(root, "scripts/authorize-promotion-runtime-override.cjs"),
|
|
287
300
|
"utf8",
|
|
@@ -983,10 +996,12 @@ for (const requiredSnippet of [
|
|
|
983
996
|
"github.event.workflow_run.event == 'push'",
|
|
984
997
|
"!startsWith(github.event.workflow_run.display_title, 'chore(release): prepare v')",
|
|
985
998
|
"!startsWith(github.event.workflow_run.display_title, 'chore(release): release v')",
|
|
986
|
-
"
|
|
999
|
+
"resume-candidate-run-id:",
|
|
1000
|
+
"resume-expected-source-tree:",
|
|
1001
|
+
"resume-buildchain-runtime-sha:",
|
|
987
1002
|
"github-release: true",
|
|
988
1003
|
"release-passport-buildchain-self-kfd: true",
|
|
989
|
-
|
|
1004
|
+
'artifact-patterns: "buildchain-package-*"',
|
|
990
1005
|
"release-passport-impact-json: .buildchain/release-impact.json",
|
|
991
1006
|
]) {
|
|
992
1007
|
if (!buildchainRefPromotionWorkflow.includes(requiredSnippet)) {
|
|
@@ -1040,6 +1055,13 @@ for (const requiredSnippet of [
|
|
|
1040
1055
|
"BUILDCHAIN_STABLE_RELEASE_POLICY: .buildchain/stable-release-policy.json",
|
|
1041
1056
|
"Consumer has no binary-distribution.yml; standalone binary dispatch is not applicable.",
|
|
1042
1057
|
"gh workflow view binary-distribution.yml",
|
|
1058
|
+
"resume-candidate-run-id:",
|
|
1059
|
+
"node .buildchain/runtime/scripts/resume-from-candidate-run.mjs",
|
|
1060
|
+
"publish-sealed-bundle-root: ${{ steps.rc.outputs.publish-sealed-bundle-root }}",
|
|
1061
|
+
"BUILDCHAIN_EXPECTED_TRANSACTION_ID: ${{ inputs.resume-transaction-id }}",
|
|
1062
|
+
"if: ${{ inputs.resume-candidate-run-id == '' }}",
|
|
1063
|
+
"Bridge Buildchain self-runtime dependencies",
|
|
1064
|
+
"ln -s .buildchain/runtime/node_modules node_modules",
|
|
1043
1065
|
]) {
|
|
1044
1066
|
if (!releaseCandidatePromoteWorkflow.includes(requiredSnippet)) {
|
|
1045
1067
|
throw new Error(`release candidate promote workflow missing KFD gate pass-through: ${requiredSnippet}`);
|
|
@@ -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) =>
|
|
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(
|
|
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
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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:
|
|
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(
|
|
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
|
+
}
|