@kungfu-tech/buildchain 3.0.8 → 3.0.9-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/promote-buildchain-ref/README.md +8 -7
- package/bin/buildchain.mjs +34 -33
- package/bin/internal/trust-release-release-handlers.mjs +5 -0
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +16 -0
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +57 -0
- package/contracts/release-cut-v1.schema.json +1 -0
- package/contracts/release-train-transition-v1.schema.json +1 -0
- package/dist/site/agent-index.json +0 -1
- package/dist/site/artifact-schemas.json +0 -2
- package/dist/site/badge-endpoint-registry.json +9 -9
- package/dist/site/badges/v1/kfd-8/aligned.json +1 -1
- package/dist/site/badges/v1/kfd-8/declared.json +1 -1
- package/dist/site/badges/v1/kfd-8/downgraded.json +1 -1
- package/dist/site/badges/v1/kfd-8/draft.json +1 -1
- package/dist/site/badges/v1/kfd-8/failed.json +1 -1
- package/dist/site/badges/v1/kfd-8/missing.json +1 -1
- package/dist/site/badges/v1/kfd-8/passed.json +1 -1
- package/dist/site/badges/v1/kfd-8/planned.json +1 -1
- package/dist/site/buildchain-contract.json +38 -34
- package/dist/site/buildchain-site.json +59 -39
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/cli-registry.json +8 -7
- package/dist/site/controller-registry.json +13 -5
- package/dist/site/kfd-claims.json +35 -8
- package/dist/site/kfd-upstream-aggregate.json +10 -10
- package/dist/site/manual-registry.json +9 -9
- package/dist/site/node-api-registry.json +1143 -320
- package/dist/site/page-registry.json +46 -26
- package/dist/site/public-surface-audit.json +19 -9
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-passport-check-manifest.json +33 -5
- package/dist/site/release-provenance.json +2 -1
- package/dist/site/schemas/release-passport-v1.schema.json +3 -0
- package/dist/site/site-manifest.json +13 -13
- package/dist/site/workflow-registry.json +19 -9
- package/docs/aws-us-elastic-runner-burst-plane.md +15 -3
- package/docs/cli-reference.md +6 -6
- package/docs/cli.md +2 -3
- package/docs/dev-alpha-candidate-patrol.md +45 -20
- package/docs/dev-delivery-warrant.md +12 -2
- package/docs/kfd-support.md +7 -7
- package/docs/node-api-reference.md +295 -246
- package/docs/release-passport.md +25 -12
- package/docs/release-train.md +54 -4
- package/docs/reusable-build-surface.md +26 -9
- package/docs/runtime-train-validation.md +6 -0
- package/docs/versioning.md +3 -2
- package/package.json +4 -3
- package/packages/core/artifact-verification-envelope.js +114 -0
- package/packages/core/buildchain-channel-identity.js +119 -0
- package/packages/core/buildchain-compatibility-proof.js +32 -0
- package/packages/core/buildchain-contract.js +7 -0
- package/packages/core/controller-evidence.js +2 -1
- package/packages/core/dev-alpha-active-release-train.js +460 -0
- package/packages/core/dev-alpha-candidate-selection.js +181 -0
- package/packages/core/dev-delivery-warrant.js +15 -4
- package/packages/core/index.js +4 -5
- package/packages/core/kfd-adopter-manifest.js +390 -0
- package/packages/core/kfd-product-gates.js +0 -300
- package/packages/core/release-blocker-priority.js +192 -0
- package/packages/core/release-passport-contract.js +219 -6
- package/packages/core/release-passport.js +139 -242
- package/packages/core/release-train.js +220 -0
- package/scripts/aws-macos-jit-controller-core.mjs +76 -0
- package/scripts/aws-macos-jit-controller.mjs +29 -0
- package/scripts/aws-macos-jit-source-rebind.mjs +503 -0
- package/scripts/buildchain-channel-router.mjs +18 -2
- package/scripts/buildchain-cli-help.mjs +4 -2
- package/scripts/buildchain-contract-lock.mjs +11 -1
- package/scripts/check-inventory.mjs +4 -4
- package/scripts/dev-alpha-candidate-patrol.mjs +196 -201
- package/scripts/generate-buildchain-kfd-witnesses.mjs +88 -94
- package/scripts/generate-channel-build-workflow.mjs +78 -31
- package/scripts/generate-site-bundle.mjs +1 -8
- package/scripts/promotion-channel-router.mjs +5 -3
- package/scripts/release-train-self-dogfood.mjs +579 -0
- package/scripts/runtime-ref-core.mjs +4 -17
- package/scripts/site-capability-metadata.mjs +3 -1
- package/dist/site/schemas/kfd-support-projection-v1.schema.json +0 -106
|
@@ -8,6 +8,8 @@ export const RELEASE_TRAIN_TRANSITION_CONTRACT =
|
|
|
8
8
|
"kungfu-buildchain-release-train-transition/v1";
|
|
9
9
|
export const RELEASE_TRAIN_OBSERVATION_CONTRACT =
|
|
10
10
|
"kungfu-buildchain-release-train-observation/v1";
|
|
11
|
+
export const RELEASE_BLOCKER_REPAIR_CONTRACT =
|
|
12
|
+
"kungfu-buildchain-release-blocker-repair/v1";
|
|
11
13
|
export const LEGACY_DEV_ALPHA_CANDIDATE_STATE_SCHEMA =
|
|
12
14
|
"kungfu-buildchain-dev-alpha-candidate-state/v1";
|
|
13
15
|
|
|
@@ -22,6 +24,7 @@ export const RELEASE_TRAIN_STATES = Object.freeze([
|
|
|
22
24
|
]);
|
|
23
25
|
|
|
24
26
|
export const RELEASE_TRAIN_SUPERSESSION_CAUSES = Object.freeze([
|
|
27
|
+
"release-blocker-repair",
|
|
25
28
|
"incompatible-semantics",
|
|
26
29
|
"alpha-base-incompatibility",
|
|
27
30
|
"invalid-authority",
|
|
@@ -518,3 +521,220 @@ export function readReleaseTrain(input) {
|
|
|
518
521
|
}
|
|
519
522
|
throw new Error("unsupported Release Train record");
|
|
520
523
|
}
|
|
524
|
+
|
|
525
|
+
function releaseBlockerLanding(input, label, { allowConflict = false } = {}) {
|
|
526
|
+
const status = text(input?.status, `${label}.status`);
|
|
527
|
+
if (status !== "landed" && !(allowConflict && status === "conflict")) {
|
|
528
|
+
throw new Error(
|
|
529
|
+
`${label}.status must be ${allowConflict ? "landed or conflict" : "landed"}`,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
const landing = {
|
|
533
|
+
status,
|
|
534
|
+
baseSha: exactSha(input.baseSha, `${label}.baseSha`),
|
|
535
|
+
landedSha:
|
|
536
|
+
status === "landed"
|
|
537
|
+
? exactSha(input.landedSha, `${label}.landedSha`)
|
|
538
|
+
: "",
|
|
539
|
+
patchRoot: contentRoot(input.patchRoot, `${label}.patchRoot`),
|
|
540
|
+
evidenceRoot: contentRoot(input.evidenceRoot, `${label}.evidenceRoot`),
|
|
541
|
+
};
|
|
542
|
+
return landing;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function releaseBlockerPublication(patchRoot, devLanding) {
|
|
546
|
+
const eligible =
|
|
547
|
+
devLanding.status === "landed" && devLanding.patchRoot === patchRoot;
|
|
548
|
+
const body = {
|
|
549
|
+
eligible,
|
|
550
|
+
reason:
|
|
551
|
+
devLanding.status === "conflict"
|
|
552
|
+
? "dev-forward-port-conflict"
|
|
553
|
+
: eligible
|
|
554
|
+
? "exact-cut-dev-patch-settled"
|
|
555
|
+
: "cut-dev-patch-root-mismatch",
|
|
556
|
+
requiredPatchRoot: patchRoot,
|
|
557
|
+
observedDevPatchRoot: devLanding.patchRoot,
|
|
558
|
+
devLandingStatus: devLanding.status,
|
|
559
|
+
};
|
|
560
|
+
return { ...body, gateRoot: releaseTrainRoot(body) };
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function buildReleaseBlockerRepair(activeTrainInput, input = {}) {
|
|
564
|
+
const activeTrain = validateReleaseTrain(activeTrainInput);
|
|
565
|
+
if (activeTrain.state.status !== "repair-required") {
|
|
566
|
+
throw new Error(
|
|
567
|
+
"release-blocker repair requires the active train to be repair-required",
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
const expectedStateRoot = contentRoot(
|
|
571
|
+
input.expectedStateRoot,
|
|
572
|
+
"expectedStateRoot",
|
|
573
|
+
);
|
|
574
|
+
if (expectedStateRoot !== activeTrain.state.stateRoot) {
|
|
575
|
+
throw new Error("release-blocker repair compare-and-swap failed");
|
|
576
|
+
}
|
|
577
|
+
const patchRoot = contentRoot(input.patchRoot, "patchRoot");
|
|
578
|
+
const blockerRoot = contentRoot(input.blockerRoot, "blockerRoot");
|
|
579
|
+
const authorityRoots = sortedRoots(input.authorityRoots, "authorityRoots");
|
|
580
|
+
const createdAt = timestamp(input.createdAt, "createdAt");
|
|
581
|
+
const cutLanding = releaseBlockerLanding(
|
|
582
|
+
{
|
|
583
|
+
status: "landed",
|
|
584
|
+
baseSha: activeTrain.releaseCut.candidateSha,
|
|
585
|
+
landedSha: input.cutCandidateSha,
|
|
586
|
+
patchRoot: input.cutPatchRoot,
|
|
587
|
+
evidenceRoot: input.cutLandingEvidenceRoot,
|
|
588
|
+
},
|
|
589
|
+
"cutLanding",
|
|
590
|
+
);
|
|
591
|
+
if (cutLanding.patchRoot !== patchRoot) {
|
|
592
|
+
throw new Error(
|
|
593
|
+
"cut landing must preserve the declared release-blocker patch root",
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
const devLanding = releaseBlockerLanding(
|
|
597
|
+
{
|
|
598
|
+
status: input.devLandingStatus,
|
|
599
|
+
baseSha: input.devBaseSha,
|
|
600
|
+
landedSha: input.devLandingSha,
|
|
601
|
+
patchRoot: input.devPatchRoot,
|
|
602
|
+
evidenceRoot: input.devLandingEvidenceRoot,
|
|
603
|
+
},
|
|
604
|
+
"devLanding",
|
|
605
|
+
{ allowConflict: true },
|
|
606
|
+
);
|
|
607
|
+
const priorCut = activeTrain.releaseCut;
|
|
608
|
+
const successorTrain = createReleaseTrain({
|
|
609
|
+
repository: priorCut.repository,
|
|
610
|
+
sourceBranch: priorCut.sourceBranch,
|
|
611
|
+
targetBranch: priorCut.targetBranch,
|
|
612
|
+
originDevSha: priorCut.originDevSha,
|
|
613
|
+
candidateSha: cutLanding.landedSha,
|
|
614
|
+
candidateTreeSha: exactSha(
|
|
615
|
+
input.cutCandidateTreeSha,
|
|
616
|
+
"cutCandidateTreeSha",
|
|
617
|
+
),
|
|
618
|
+
alphaBaseSha: priorCut.alphaBaseSha,
|
|
619
|
+
buildchainRuntimeSha: priorCut.buildchainRuntimeSha,
|
|
620
|
+
generation: priorCut.generation + 1,
|
|
621
|
+
authorityRoots: [
|
|
622
|
+
...new Set([...priorCut.authorityRoots, ...authorityRoots]),
|
|
623
|
+
].sort(),
|
|
624
|
+
supersession: {
|
|
625
|
+
cause: "release-blocker-repair",
|
|
626
|
+
priorCutRoot: priorCut.cutRoot,
|
|
627
|
+
},
|
|
628
|
+
createdAt,
|
|
629
|
+
});
|
|
630
|
+
const supersededTrain = transitionReleaseTrain(activeTrain, {
|
|
631
|
+
to: "superseded",
|
|
632
|
+
expectedStateRoot,
|
|
633
|
+
event: "release-blocker-successor-cut",
|
|
634
|
+
reason:
|
|
635
|
+
"a rooted release-blocker repair advanced the active candidate generation",
|
|
636
|
+
authorityRoots,
|
|
637
|
+
supersessionCause: "release-blocker-repair",
|
|
638
|
+
replacementCutRoot: successorTrain.releaseCut.cutRoot,
|
|
639
|
+
replacementCandidateSha: successorTrain.releaseCut.candidateSha,
|
|
640
|
+
recordedAt: createdAt,
|
|
641
|
+
});
|
|
642
|
+
const publication = releaseBlockerPublication(patchRoot, devLanding);
|
|
643
|
+
const body = {
|
|
644
|
+
schemaVersion: 1,
|
|
645
|
+
contract: RELEASE_BLOCKER_REPAIR_CONTRACT,
|
|
646
|
+
blockerRoot,
|
|
647
|
+
patchRoot,
|
|
648
|
+
priorTrain: activeTrain,
|
|
649
|
+
supersededTrain,
|
|
650
|
+
successorTrain,
|
|
651
|
+
cutLanding,
|
|
652
|
+
devLanding,
|
|
653
|
+
candidateBuild: {
|
|
654
|
+
eligible: true,
|
|
655
|
+
candidateSha: successorTrain.releaseCut.candidateSha,
|
|
656
|
+
candidateTreeSha: successorTrain.releaseCut.candidateTreeSha,
|
|
657
|
+
generation: successorTrain.releaseCut.generation,
|
|
658
|
+
cutRoot: successorTrain.releaseCut.cutRoot,
|
|
659
|
+
reason: "rooted-cut-landing",
|
|
660
|
+
},
|
|
661
|
+
publication,
|
|
662
|
+
authorityRoots,
|
|
663
|
+
createdAt,
|
|
664
|
+
};
|
|
665
|
+
return { ...body, repairRoot: releaseTrainRoot(body) };
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
export function createReleaseBlockerRepair(activeTrainInput, input = {}) {
|
|
669
|
+
return buildReleaseBlockerRepair(activeTrainInput, input);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export function validateReleaseBlockerRepair(input) {
|
|
673
|
+
if (
|
|
674
|
+
input?.contract !== RELEASE_BLOCKER_REPAIR_CONTRACT ||
|
|
675
|
+
Number(input?.schemaVersion) !== 1
|
|
676
|
+
) {
|
|
677
|
+
throw new Error(
|
|
678
|
+
`release-blocker repair must use ${RELEASE_BLOCKER_REPAIR_CONTRACT}`,
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
const rebuilt = buildReleaseBlockerRepair(input.priorTrain, {
|
|
682
|
+
expectedStateRoot: input.priorTrain?.state?.stateRoot,
|
|
683
|
+
blockerRoot: input.blockerRoot,
|
|
684
|
+
patchRoot: input.patchRoot,
|
|
685
|
+
cutCandidateSha: input.cutLanding?.landedSha,
|
|
686
|
+
cutCandidateTreeSha: input.successorTrain?.releaseCut?.candidateTreeSha,
|
|
687
|
+
cutPatchRoot: input.cutLanding?.patchRoot,
|
|
688
|
+
cutLandingEvidenceRoot: input.cutLanding?.evidenceRoot,
|
|
689
|
+
devLandingStatus: input.devLanding?.status,
|
|
690
|
+
devBaseSha: input.devLanding?.baseSha,
|
|
691
|
+
devLandingSha: input.devLanding?.landedSha,
|
|
692
|
+
devPatchRoot: input.devLanding?.patchRoot,
|
|
693
|
+
devLandingEvidenceRoot: input.devLanding?.evidenceRoot,
|
|
694
|
+
authorityRoots: input.authorityRoots,
|
|
695
|
+
createdAt: input.createdAt,
|
|
696
|
+
});
|
|
697
|
+
if (input.repairRoot !== rebuilt.repairRoot) {
|
|
698
|
+
throw new Error("release-blocker repair root does not match its content");
|
|
699
|
+
}
|
|
700
|
+
if (releaseTrainRoot(input) !== releaseTrainRoot(rebuilt)) {
|
|
701
|
+
throw new Error(
|
|
702
|
+
"release-blocker repair content drifted from its rooted contract",
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
return clone(input);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
export function settleReleaseBlockerDevLanding(repairInput, input = {}) {
|
|
709
|
+
const repair = validateReleaseBlockerRepair(repairInput);
|
|
710
|
+
if (
|
|
711
|
+
contentRoot(input.expectedRepairRoot, "expectedRepairRoot") !==
|
|
712
|
+
repair.repairRoot
|
|
713
|
+
) {
|
|
714
|
+
throw new Error(
|
|
715
|
+
"release-blocker repair settlement compare-and-swap failed",
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
const patchRoot = contentRoot(input.patchRoot, "patchRoot");
|
|
719
|
+
if (patchRoot !== repair.patchRoot) {
|
|
720
|
+
throw new Error(
|
|
721
|
+
"dev landing settlement must preserve the release-blocker patch root",
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
return buildReleaseBlockerRepair(repair.priorTrain, {
|
|
725
|
+
expectedStateRoot: repair.priorTrain.state.stateRoot,
|
|
726
|
+
blockerRoot: repair.blockerRoot,
|
|
727
|
+
patchRoot: repair.patchRoot,
|
|
728
|
+
cutCandidateSha: repair.cutLanding.landedSha,
|
|
729
|
+
cutCandidateTreeSha: repair.successorTrain.releaseCut.candidateTreeSha,
|
|
730
|
+
cutPatchRoot: repair.cutLanding.patchRoot,
|
|
731
|
+
cutLandingEvidenceRoot: repair.cutLanding.evidenceRoot,
|
|
732
|
+
devLandingStatus: "landed",
|
|
733
|
+
devBaseSha: input.devBaseSha,
|
|
734
|
+
devLandingSha: input.devLandingSha,
|
|
735
|
+
devPatchRoot: patchRoot,
|
|
736
|
+
devLandingEvidenceRoot: input.devLandingEvidenceRoot,
|
|
737
|
+
authorityRoots: repair.authorityRoots,
|
|
738
|
+
createdAt: repair.createdAt,
|
|
739
|
+
});
|
|
740
|
+
}
|
|
@@ -56,6 +56,17 @@ function source(values) {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
function previousSource(values) {
|
|
60
|
+
return {
|
|
61
|
+
sha: exactSha(values.previousSourceSha),
|
|
62
|
+
ref: exact(
|
|
63
|
+
values.previousSourceRef || values.sourceRef,
|
|
64
|
+
/^refs\/heads\/[A-Za-z0-9._/-]+$/,
|
|
65
|
+
"previousSourceRef",
|
|
66
|
+
),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
59
70
|
function campaignId(value) {
|
|
60
71
|
return exact(value, /^[a-z0-9][a-z0-9-]{2,47}$/, "campaignId");
|
|
61
72
|
}
|
|
@@ -192,6 +203,71 @@ export function createMacosJitCampaignPlan(values = {}) {
|
|
|
192
203
|
return { ...plan, digest: digest(plan) };
|
|
193
204
|
}
|
|
194
205
|
|
|
206
|
+
export function createMacosJitSourceRebindPlan(values = {}) {
|
|
207
|
+
const id = campaignId(values.campaignId);
|
|
208
|
+
const boundSource = source(values);
|
|
209
|
+
const priorSource = previousSource(values);
|
|
210
|
+
if (boundSource.sha === priorSource.sha) {
|
|
211
|
+
throw new Error("sourceSha must differ from previousSourceSha");
|
|
212
|
+
}
|
|
213
|
+
if (boundSource.ref !== priorSource.ref) {
|
|
214
|
+
throw new Error("sourceRef must remain unchanged during campaign rebind");
|
|
215
|
+
}
|
|
216
|
+
const aws = commonAws(values);
|
|
217
|
+
const regionConfig = macosJitRegionConfig(aws.region);
|
|
218
|
+
const workflowId = exact(values.workflowId, /^\d+$/, "workflowId");
|
|
219
|
+
if (workflowId !== MACOS_EC2_JIT.workflowId) {
|
|
220
|
+
throw new Error(`workflowId must be ${MACOS_EC2_JIT.workflowId}`);
|
|
221
|
+
}
|
|
222
|
+
const plan = {
|
|
223
|
+
schemaVersion: 1,
|
|
224
|
+
contract: AWS_MACOS_JIT_CONTROLLER_CONTRACT,
|
|
225
|
+
kind: "campaign-source-rebind-plan",
|
|
226
|
+
repository: repository(values.repository),
|
|
227
|
+
account: {
|
|
228
|
+
id: exact(values.accountId, /^\d{12}$/, "accountId"),
|
|
229
|
+
},
|
|
230
|
+
campaign: { id },
|
|
231
|
+
previousSource: priorSource,
|
|
232
|
+
source: boundSource,
|
|
233
|
+
github: {
|
|
234
|
+
workflowId,
|
|
235
|
+
requiredState: "disabled_manually",
|
|
236
|
+
},
|
|
237
|
+
aws: {
|
|
238
|
+
...aws,
|
|
239
|
+
hostId: exact(values.hostId, /^h-[0-9a-f]+$/, "hostId"),
|
|
240
|
+
instanceId: exact(values.instanceId, /^i-[0-9a-f]+$/, "instanceId"),
|
|
241
|
+
},
|
|
242
|
+
safety: {
|
|
243
|
+
applyMode: values.execute === true ? "execute" : "dry-run",
|
|
244
|
+
noAllocation: true,
|
|
245
|
+
noDispatch: true,
|
|
246
|
+
forwardOnlySource: true,
|
|
247
|
+
sameSourceRefRequired: true,
|
|
248
|
+
workflowDisabledRequired: true,
|
|
249
|
+
zeroPriorJobsRequired: true,
|
|
250
|
+
zeroPriorArtifactsRequired: true,
|
|
251
|
+
zeroJitResidueRequired: true,
|
|
252
|
+
zeroEvidenceRequired: true,
|
|
253
|
+
exactCampaignResourcesRequired: true,
|
|
254
|
+
compensatedRollbackRequired: true,
|
|
255
|
+
budget: {
|
|
256
|
+
name: regionConfig.budgetName,
|
|
257
|
+
limitUsd: MACOS_EC2_JIT.budgetLimitUsd,
|
|
258
|
+
metrics: ["UnblendedCost"],
|
|
259
|
+
dimensionFilter: {
|
|
260
|
+
usageTypes: regionConfig.budgetUsageTypes,
|
|
261
|
+
operation: MACOS_EC2_JIT.budgetOperation,
|
|
262
|
+
regions: regionConfig.budgetRegions,
|
|
263
|
+
},
|
|
264
|
+
requiredActualThresholds: [80, 95],
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
return { ...plan, digest: digest(plan) };
|
|
269
|
+
}
|
|
270
|
+
|
|
195
271
|
export function macosAllocateHostsArgs(plan) {
|
|
196
272
|
if (
|
|
197
273
|
plan?.contract !== AWS_MACOS_JIT_CONTROLLER_CONTRACT ||
|
|
@@ -7,12 +7,14 @@ import {
|
|
|
7
7
|
createMacosJitCampaignPlan,
|
|
8
8
|
createMacosJitClosePlan,
|
|
9
9
|
createMacosJitJobPlan,
|
|
10
|
+
createMacosJitSourceRebindPlan,
|
|
10
11
|
macosAllocateHostsArgs,
|
|
11
12
|
macosReleaseHostsArgs,
|
|
12
13
|
macosRunInstancesArgs,
|
|
13
14
|
} from "./aws-macos-jit-controller-core.mjs";
|
|
14
15
|
import { MACOS_EC2_JIT_REGIONS } from "./aws-macos-jit-core.mjs";
|
|
15
16
|
import { executeMacosJitJob } from "./aws-macos-jit-job-controller.mjs";
|
|
17
|
+
import { executeMacosJitSourceRebind } from "./aws-macos-jit-source-rebind.mjs";
|
|
16
18
|
import {
|
|
17
19
|
assertDryRun,
|
|
18
20
|
assertAllowedPolicySimulation,
|
|
@@ -498,6 +500,22 @@ function confirm(plan) {
|
|
|
498
500
|
if (arg("confirm-campaign-id") !== plan.campaign.id) {
|
|
499
501
|
throw new Error("--confirm-campaign-id must equal the campaign id");
|
|
500
502
|
}
|
|
503
|
+
if (plan.kind === "campaign-source-rebind-plan") {
|
|
504
|
+
if (arg("confirm-previous-source-sha") !== plan.previousSource.sha) {
|
|
505
|
+
throw new Error(
|
|
506
|
+
"--confirm-previous-source-sha must equal previousSourceSha",
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
if (arg("confirm-host-id") !== plan.aws.hostId) {
|
|
510
|
+
throw new Error("--confirm-host-id must equal the exact host id");
|
|
511
|
+
}
|
|
512
|
+
if (arg("confirm-instance-id") !== plan.aws.instanceId) {
|
|
513
|
+
throw new Error("--confirm-instance-id must equal the exact instance id");
|
|
514
|
+
}
|
|
515
|
+
if (!flag("confirm-zero-allocation")) {
|
|
516
|
+
throw new Error("--confirm-zero-allocation is required");
|
|
517
|
+
}
|
|
518
|
+
}
|
|
501
519
|
}
|
|
502
520
|
|
|
503
521
|
function emit(plan, mode, execute, operation) {
|
|
@@ -523,6 +541,17 @@ export function main() {
|
|
|
523
541
|
executeMacosJitCampaignLaunch(plan, { profile: arg("aws-profile") }),
|
|
524
542
|
);
|
|
525
543
|
}
|
|
544
|
+
if (["plan-rebind", "rebind-campaign"].includes(mode)) {
|
|
545
|
+
const plan = createMacosJitSourceRebindPlan({
|
|
546
|
+
...commonValues(execute),
|
|
547
|
+
previousSourceSha: arg("previous-source-sha"),
|
|
548
|
+
previousSourceRef: arg("previous-source-ref"),
|
|
549
|
+
workflowId: arg("workflow-id"),
|
|
550
|
+
hostId: arg("host-id"),
|
|
551
|
+
instanceId: arg("instance-id"),
|
|
552
|
+
});
|
|
553
|
+
return emit(plan, mode, execute, () => executeMacosJitSourceRebind(plan, { profile: arg("aws-profile") }));
|
|
554
|
+
}
|
|
526
555
|
if (["plan-job", "run-job"].includes(mode)) {
|
|
527
556
|
const plan = createMacosJitJobPlan({
|
|
528
557
|
...commonValues(execute),
|