@kungfu-tech/buildchain 3.0.9-alpha.1 → 3.0.9-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/bin/buildchain.mjs +9 -1
- package/contracts/dev-delivery-authority-v2.schema.json +253 -0
- package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
- package/contracts/next-development-request-v1.schema.json +66 -0
- package/contracts/next-development-transition-v1.schema.json +292 -0
- package/dist/site/agent-index.json +1 -0
- package/dist/site/artifact-schemas.json +2 -0
- package/dist/site/buildchain-contract.json +74 -14
- package/dist/site/buildchain-site.json +334 -36
- package/dist/site/capability-registry.json +7 -6
- package/dist/site/cli-registry.json +41 -2
- package/dist/site/kfd-claims.json +193 -9
- package/dist/site/kfd-upstream-aggregate.json +9 -9
- package/dist/site/manual-registry.json +23 -7
- package/dist/site/node-api-registry.json +7789 -4648
- package/dist/site/page-registry.json +315 -25
- package/dist/site/public-surface-audit.json +353 -8
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-passport-check-manifest.json +1 -0
- package/dist/site/release-provenance.json +12 -0
- package/dist/site/schemas/dev-delivery-authority-v2.schema.json +442 -0
- package/dist/site/schemas/release-passport-v1.schema.json +3 -0
- package/dist/site/site-manifest.json +19 -11
- package/dist/site/workflow-registry.json +15 -7
- package/docs/MAP.md +5 -2
- package/docs/adopter-delivery-gate.md +106 -0
- package/docs/aws-us-elastic-runner-burst-plane.md +30 -3
- package/docs/cli-reference.md +200 -13
- package/docs/dev-alpha-candidate-patrol.md +8 -0
- package/docs/dev-delivery-qualification-landing-adr.md +137 -0
- package/docs/dev-delivery-warrant.md +149 -22
- package/docs/kfd-support.md +7 -2
- package/docs/next-development-transition.md +119 -0
- package/docs/node-api-reference.md +381 -204
- package/docs/release-governance.md +10 -7
- package/docs/release-passport.md +8 -2
- package/docs/versioning.md +4 -1
- package/package.json +21 -6
- package/packages/core/README.md +25 -0
- package/packages/core/adopter-delivery-gate.js +576 -0
- package/packages/core/adopter-delivery-json.js +66 -0
- package/packages/core/adopter-delivery-passport.js +259 -0
- package/packages/core/adopter-delivery-vectors.js +158 -0
- package/packages/core/adopter-delivery-vectors.json +77 -0
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/buildchain-agent-manuals.js +1 -0
- package/packages/core/buildchain-channel-identity.js +2 -3
- package/packages/core/buildchain-compatibility-proof.js +22 -0
- package/packages/core/buildchain-delivery-bootstrap.js +240 -0
- package/packages/core/buildchain-delivery-infrastructure.js +164 -0
- package/packages/core/channel-candidate.js +8 -0
- package/packages/core/channel-promotion-baseline.js +52 -0
- package/packages/core/dev-alpha-candidate-selection.js +10 -2
- package/packages/core/dev-delivery-authority.js +996 -0
- package/packages/core/dev-delivery-native-proof.js +418 -0
- package/packages/core/dev-delivery-warrant-settlement.js +67 -20
- package/packages/core/dev-delivery-warrant.js +128 -46
- package/packages/core/kfd-adopter-category-driver.js +167 -0
- package/packages/core/kfd-adopter-manifest.js +49 -50
- package/packages/core/legacy-kfd-adopter-driver.js +167 -0
- package/packages/core/next-development-candidate-reservation.js +186 -0
- package/packages/core/next-development-controller.js +726 -0
- package/packages/core/next-development-projection.js +288 -0
- package/packages/core/next-development-transition.js +738 -0
- package/packages/core/paper-agent-entry.js +7 -4
- package/packages/core/paper.js +14 -7
- package/packages/core/release-passport-contract.js +10 -6
- package/packages/core/release-passport.js +29 -12
- package/scripts/aws-macos-jit-controller-core.mjs +239 -4
- package/scripts/aws-macos-jit-controller.mjs +198 -2
- package/scripts/aws-macos-jit-instance-rehydrate.mjs +260 -0
- package/scripts/aws-macos-jit-source-rebind.mjs +235 -14
- package/scripts/aws-macos-jit.mjs +12 -0
- package/scripts/buildchain-cli-help.mjs +9 -2
- package/scripts/check-internal-architecture.mjs +1 -0
- package/scripts/check-inventory.mjs +12 -1
- package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
- package/scripts/dev-delivery-authority.mjs +368 -0
- package/scripts/dev-delivery-native-run.mjs +235 -0
- package/scripts/dev-delivery-proof.mjs +64 -2
- package/scripts/dev-delivery-two-phase-resume.mjs +90 -0
- package/scripts/dev-delivery-two-phase.mjs +577 -0
- package/scripts/dev-delivery-warrant.mjs +47 -5
- package/scripts/dev-pr-delivery-warrant.mjs +19 -14
- package/scripts/generate-buildchain-kfd-witnesses.mjs +2 -2
- package/scripts/generate-channel-build-workflow.mjs +4 -0
- package/scripts/generate-next-development-guidance.mjs +49 -0
- package/scripts/generate-site-bundle.mjs +8 -3
- package/scripts/init-repo.mjs +135 -62
- package/scripts/next-development-self-dogfood-harness.mjs +409 -0
- package/scripts/next-development-self-dogfood.mjs +532 -0
- package/scripts/next-development-transition.mjs +47 -0
- package/scripts/release-candidate-tail-reseal.mjs +426 -0
- package/scripts/seal-artifact-signing-requests.mjs +7 -4
- package/scripts/site-capability-metadata.mjs +23 -1
- package/scripts/stable-candidate-qualification.mjs +7 -7
- package/scripts/workflow-call-contract.mjs +1 -1
- package/templates/native-dev-delivery.yml +86 -0
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
workCheck,
|
|
14
14
|
} from "./paper-repository.js";
|
|
15
15
|
import { mergePublicationRehearsalAgentInstructions } from "./publication-rehearsal-projection.js";
|
|
16
|
+
import { mergeNextDevelopmentAgentInstructions } from "./next-development-projection.js";
|
|
16
17
|
|
|
17
18
|
export const PAPER_AGENT_ENTRY_CONTRACT = "kungfu-buildchain-paper-agent-entry";
|
|
18
19
|
export const PAPER_AGENT_ENTRY_SCHEMA_VERSION = 1;
|
|
@@ -168,10 +169,12 @@ export function paperAgentEntryFiles({
|
|
|
168
169
|
[PAPER_PATHS.agentEntry, jsonText(entry)],
|
|
169
170
|
[
|
|
170
171
|
PAPER_PATHS.agentInstructions,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
mergeNextDevelopmentAgentInstructions(
|
|
173
|
+
mergePublicationRehearsalAgentInstructions(
|
|
174
|
+
mergePaperAgentEntryInstructions(currentAgents, {
|
|
175
|
+
developmentRef: resolvedDevelopmentRef,
|
|
176
|
+
}),
|
|
177
|
+
),
|
|
175
178
|
),
|
|
176
179
|
],
|
|
177
180
|
]);
|
package/packages/core/paper.js
CHANGED
|
@@ -51,6 +51,11 @@ import {
|
|
|
51
51
|
projectPublicationRehearsalToml,
|
|
52
52
|
publicationRehearsalWorkflow,
|
|
53
53
|
} from "./publication-rehearsal-projection.js";
|
|
54
|
+
import {
|
|
55
|
+
appendNextDevelopmentToml,
|
|
56
|
+
nextDevelopmentWorkflowHeader,
|
|
57
|
+
projectNextDevelopmentToml,
|
|
58
|
+
} from "./next-development-projection.js";
|
|
54
59
|
|
|
55
60
|
export { PAPER_PATHS, resolvePaperRepository } from "./paper-repository.js";
|
|
56
61
|
export {
|
|
@@ -356,7 +361,7 @@ immutable_base_url = ${tomlString(joinUrl(siteBaseUrl, "archive").replace(/\/$/,
|
|
|
356
361
|
registry_path = ".buildchain/publication/publication-registry.json"
|
|
357
362
|
`
|
|
358
363
|
: "";
|
|
359
|
-
return appendPublicationRehearsalToml(`schema = 1
|
|
364
|
+
return appendNextDevelopmentToml(appendPublicationRehearsalToml(`schema = 1
|
|
360
365
|
|
|
361
366
|
[project]
|
|
362
367
|
type = "publication-artifact"
|
|
@@ -390,14 +395,14 @@ command = "make pdf"
|
|
|
390
395
|
|
|
391
396
|
[lifecycle.verify]
|
|
392
397
|
command = "make check"
|
|
393
|
-
`);
|
|
398
|
+
`));
|
|
394
399
|
}
|
|
395
400
|
|
|
396
401
|
function scaffoldBuildWorkflow(
|
|
397
402
|
buildchainSha,
|
|
398
403
|
{ artifactName = "paper-publication" } = {},
|
|
399
404
|
) {
|
|
400
|
-
return
|
|
405
|
+
return `${nextDevelopmentWorkflowHeader()}name: Build
|
|
401
406
|
|
|
402
407
|
on:
|
|
403
408
|
workflow_dispatch:
|
|
@@ -425,7 +430,7 @@ jobs:
|
|
|
425
430
|
}
|
|
426
431
|
|
|
427
432
|
function scaffoldVerifyWorkflow(buildchainSha) {
|
|
428
|
-
return
|
|
433
|
+
return `${nextDevelopmentWorkflowHeader()}name: Verify
|
|
429
434
|
|
|
430
435
|
on:
|
|
431
436
|
pull_request:
|
|
@@ -456,7 +461,7 @@ function scaffoldReleaseWorkflow(
|
|
|
456
461
|
const passportInput = releasePassportProductName
|
|
457
462
|
? ` release-passport-product-name: ${JSON.stringify(releasePassportProductName)}\n`
|
|
458
463
|
: "";
|
|
459
|
-
return
|
|
464
|
+
return `${nextDevelopmentWorkflowHeader()}name: Paper Release
|
|
460
465
|
|
|
461
466
|
on:
|
|
462
467
|
workflow_dispatch:
|
|
@@ -1017,8 +1022,10 @@ function migrationFiles({
|
|
|
1017
1022
|
const files = new Map([
|
|
1018
1023
|
[
|
|
1019
1024
|
PAPER_PATHS.config,
|
|
1020
|
-
|
|
1021
|
-
|
|
1025
|
+
projectNextDevelopmentToml(
|
|
1026
|
+
projectPublicationRehearsalToml(
|
|
1027
|
+
fs.readFileSync(path.resolve(cwd, PAPER_PATHS.config), "utf8"),
|
|
1028
|
+
),
|
|
1022
1029
|
),
|
|
1023
1030
|
],
|
|
1024
1031
|
[PAPER_PATHS.contractLock, contractLockText],
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
installedKfdPackageArtifactRoot,
|
|
11
11
|
validateKfdAdopterReleaseBinding,
|
|
12
12
|
} from "./artifact-verification-envelope.js";
|
|
13
|
+
import { normalizeAdopterDeliveryPassportBinding } from "./adopter-delivery-passport.js";
|
|
13
14
|
|
|
14
15
|
export const RELEASE_PASSPORT_CONTRACT = "kungfu-buildchain-release-passport";
|
|
15
16
|
export const RELEASE_CHECK_REPORT_CONTRACT = "kungfu-buildchain-release-check-report";
|
|
@@ -110,6 +111,7 @@ export const RELEASE_PASSPORT_SCHEMA = {
|
|
|
110
111
|
"kfd-1": OBJECT,
|
|
111
112
|
"kfd-2": OBJECT,
|
|
112
113
|
"kfd-3": OBJECT,
|
|
114
|
+
adopterDelivery: OBJECT,
|
|
113
115
|
kfdAdopter: OBJECT,
|
|
114
116
|
kfdSupport: OBJECT,
|
|
115
117
|
},
|
|
@@ -134,6 +136,7 @@ const BUILDCHAIN_AGGREGATION_FIELDS = [
|
|
|
134
136
|
"platformArtifactManifests",
|
|
135
137
|
"distTagPromotion",
|
|
136
138
|
"controllerReceipts",
|
|
139
|
+
"adopterDelivery",
|
|
137
140
|
"kfdAdopter",
|
|
138
141
|
"kfdSupport",
|
|
139
142
|
"githubArtifactAttestations",
|
|
@@ -356,7 +359,7 @@ export function defaultReleaseLlmsText({ tag = "", passportPath = "buildchain.re
|
|
|
356
359
|
].join("\n");
|
|
357
360
|
}
|
|
358
361
|
|
|
359
|
-
export function buildReleaseArtifactEvidence({ normalizedAssets = [], repository = "", tag = "", sourceSha = "", workflow = {}, kfdAdopter } = {}) {
|
|
362
|
+
export function buildReleaseArtifactEvidence({ normalizedAssets = [], repository = "", tag = "", sourceSha = "", workflow = {}, adopterDelivery, kfdAdopter } = {}) {
|
|
360
363
|
return {
|
|
361
364
|
schemaVersion: 1,
|
|
362
365
|
contract: "kungfu-buildchain-artifact-evidence",
|
|
@@ -381,6 +384,7 @@ export function buildReleaseArtifactEvidence({ normalizedAssets = [], repository
|
|
|
381
384
|
sha256: asset.sha256, url: asset.url, githubAssetId: asset.githubAssetId,
|
|
382
385
|
attestation: passportOptional(asset.attestation || ""),
|
|
383
386
|
})),
|
|
387
|
+
...(adopterDelivery ? { adopterDelivery: normalizeAdopterDeliveryPassportBinding(adopterDelivery) } : {}),
|
|
384
388
|
...(kfdAdopter ? { kfdAdopter: structuredClone(kfdAdopter) } : {}),
|
|
385
389
|
};
|
|
386
390
|
}
|
|
@@ -405,7 +409,7 @@ export function prepareReleasePassportKfdSections({ kfd1, kfd2Claims, kfd3, kfdA
|
|
|
405
409
|
};
|
|
406
410
|
}
|
|
407
411
|
|
|
408
|
-
export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], comparisonMatrix, sourceSha = "", checkedAt } = {}) {
|
|
412
|
+
export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], comparisonMatrix, expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", sourceSha = "", checkedAt } = {}) {
|
|
409
413
|
if (!manifest) {
|
|
410
414
|
if (comparisonMatrix || gateResults.length > 0) {
|
|
411
415
|
throw new Error("KFD support and product-gate inputs require --kfd-adopter-manifest-json; --kfd-support-matrix-json is comparison-only");
|
|
@@ -414,7 +418,7 @@ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], c
|
|
|
414
418
|
}
|
|
415
419
|
const manifestGate = createKfdAdopterManifestGate({
|
|
416
420
|
manifest, packageArtifactRoot: installedKfdPackageArtifactRoot(), gateResults,
|
|
417
|
-
expectedSourceSha: sourceSha, checkedAt,
|
|
421
|
+
authorityPath: "kfd-adopter-manifest.json", expectedAdopterId, expectedSourceRepository, expectedSourceSha: sourceSha, checkedAt,
|
|
418
422
|
});
|
|
419
423
|
const legacyProjection = createKfdLegacySupportMatrixProjection({ manifest, manifestGate });
|
|
420
424
|
if (comparisonMatrix) {
|
|
@@ -425,18 +429,18 @@ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], c
|
|
|
425
429
|
}
|
|
426
430
|
return {
|
|
427
431
|
manifest, manifestGate, legacyProjection,
|
|
428
|
-
binding: createKfdAdopterReleaseBinding({ manifest, manifestGate, legacyProjection, expectedSourceSha: sourceSha }),
|
|
432
|
+
binding: createKfdAdopterReleaseBinding({ manifest, manifestGate, legacyProjection, expectedAdopterId, expectedSourceRepository, expectedSourceSha: sourceSha }),
|
|
429
433
|
};
|
|
430
434
|
}
|
|
431
435
|
|
|
432
|
-
export function validateKfdAdopterReleaseEvidence({ binding, artifactBinding, manifest, manifestGate, legacyProjection, passportLegacyProjection, expectedSourceSha = "" } = {}) {
|
|
436
|
+
export function validateKfdAdopterReleaseEvidence({ binding, artifactBinding, manifest, manifestGate, legacyProjection, passportLegacyProjection, expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", expectedSourceSha = "" } = {}) {
|
|
433
437
|
if (!binding) {
|
|
434
438
|
return passportLegacyProjection
|
|
435
439
|
? [{ code: "kfdSupport.authority", message: "legacy KFD support projection requires the standard adopter manifest binding" }]
|
|
436
440
|
: [];
|
|
437
441
|
}
|
|
438
442
|
const issues = validateKfdAdopterReleaseBinding(binding, {
|
|
439
|
-
manifest, manifestGate, legacyProjection, expectedSourceSha,
|
|
443
|
+
manifest, manifestGate, legacyProjection, expectedAdopterId, expectedSourceRepository, expectedSourceSha,
|
|
440
444
|
}).issues.map((entry) => ({ code: `kfdAdopter.${entry.path || entry.code}`, message: entry.message, details: entry }));
|
|
441
445
|
if (!artifactBinding || passportStableJson(artifactBinding) !== passportStableJson(binding)) {
|
|
442
446
|
issues.push({ code: "kfdAdopter.artifactEvidence", message: "release passport and artifact evidence must bind the same exact KFD adopter closure" });
|
|
@@ -33,6 +33,10 @@ import { normalizeControllerReceiptReferences } from "./controller-evidence.js";
|
|
|
33
33
|
import {
|
|
34
34
|
normalizeGitHubArtifactAttestationPolicy,
|
|
35
35
|
} from "./github-artifact-attestation.js";
|
|
36
|
+
import {
|
|
37
|
+
normalizeAdopterDeliveryPassportBinding,
|
|
38
|
+
validateAdopterDeliveryReleaseEvidence,
|
|
39
|
+
} from "./adopter-delivery-passport.js";
|
|
36
40
|
|
|
37
41
|
export { RELEASE_CHECK_REPORT_CONTRACT, RELEASE_PASSPORT_CONTRACT };
|
|
38
42
|
export const ARTIFACT_EVIDENCE_CONTRACT = "kungfu-buildchain-artifact-evidence";
|
|
@@ -1160,9 +1164,9 @@ function normalizePromotionRouting(value = undefined) {
|
|
|
1160
1164
|
return JSON.parse(JSON.stringify(value));
|
|
1161
1165
|
}
|
|
1162
1166
|
|
|
1163
|
-
export function createArtifactEvidence({ assets = [], repository = "", tag = "", sourceSha = "", workflow = {}, kfdAdopter = undefined } = {}) {
|
|
1167
|
+
export function createArtifactEvidence({ assets = [], repository = "", tag = "", sourceSha = "", workflow = {}, adopterDelivery = undefined, kfdAdopter = undefined } = {}) {
|
|
1164
1168
|
const normalizedAssets = assets.map((asset, index) => normalizeAsset(asset, index));
|
|
1165
|
-
return buildReleaseArtifactEvidence({ normalizedAssets, repository, tag, sourceSha, workflow, kfdAdopter });
|
|
1169
|
+
return buildReleaseArtifactEvidence({ normalizedAssets, repository, tag, sourceSha, workflow, adopterDelivery, kfdAdopter });
|
|
1166
1170
|
}
|
|
1167
1171
|
|
|
1168
1172
|
function firstTruthy(...values) {
|
|
@@ -1187,11 +1191,13 @@ function acceptedControllerSourceShas(input) {
|
|
|
1187
1191
|
: [];
|
|
1188
1192
|
}
|
|
1189
1193
|
|
|
1190
|
-
function
|
|
1191
|
-
const
|
|
1194
|
+
function prepareReleaseAdopterArtifacts({ adopterDelivery, kfdAdopter, assets, repository, tag, sourceSha, workflow }) {
|
|
1195
|
+
const normalizedAdopterDelivery = normalizeAdopterDeliveryPassportBinding(adopterDelivery);
|
|
1196
|
+
const normalizedKfdAdopter = kfdAdopter ? structuredClone(kfdAdopter) : undefined;
|
|
1192
1197
|
return {
|
|
1193
|
-
|
|
1194
|
-
|
|
1198
|
+
normalizedAdopterDelivery,
|
|
1199
|
+
normalizedKfdAdopter,
|
|
1200
|
+
artifactEvidence: createArtifactEvidence({ assets, repository, tag, sourceSha, workflow, adopterDelivery: normalizedAdopterDelivery, kfdAdopter: normalizedKfdAdopter }),
|
|
1195
1201
|
};
|
|
1196
1202
|
}
|
|
1197
1203
|
|
|
@@ -1229,6 +1235,7 @@ export function createReleasePassport({
|
|
|
1229
1235
|
kfd1 = undefined,
|
|
1230
1236
|
kfd2Claims = [],
|
|
1231
1237
|
kfd3 = undefined,
|
|
1238
|
+
adopterDelivery = undefined,
|
|
1232
1239
|
kfdAdopter = undefined,
|
|
1233
1240
|
kfdAdopterManifestEvidencePath = "",
|
|
1234
1241
|
kfdAdopterGateEvidencePath = "",
|
|
@@ -1244,8 +1251,8 @@ export function createReleasePassport({
|
|
|
1244
1251
|
checkedAt = "",
|
|
1245
1252
|
} = {}) {
|
|
1246
1253
|
const normalizedTag = nonEmptyString(tag, "tag");
|
|
1247
|
-
const {
|
|
1248
|
-
kfdAdopter, assets, repository, tag: normalizedTag, sourceSha, workflow,
|
|
1254
|
+
const { normalizedAdopterDelivery, normalizedKfdAdopter, artifactEvidence } = prepareReleaseAdopterArtifacts({
|
|
1255
|
+
adopterDelivery, kfdAdopter, assets, repository, tag: normalizedTag, sourceSha, workflow,
|
|
1249
1256
|
});
|
|
1250
1257
|
const normalizedPublishEvidence = normalizePublishEvidence(publishEvidence);
|
|
1251
1258
|
const normalizedPackageSet = normalizePackageSet(packageSet, { packageName, packageVersion, publish });
|
|
@@ -1405,6 +1412,7 @@ export function createReleasePassport({
|
|
|
1405
1412
|
["buildFacts", normalizedBuildFacts],
|
|
1406
1413
|
["platformArtifactManifests", normalizedPlatformArtifactManifests],
|
|
1407
1414
|
["distTagPromotion", normalizedDistTagPromotionEvidence],
|
|
1415
|
+
["adopterDelivery", normalizedAdopterDelivery],
|
|
1408
1416
|
...kfdParts.sectionEntries,
|
|
1409
1417
|
["kfdAgentHub", normalizedKfdAgentHub],
|
|
1410
1418
|
["invariantPassports", invariantPassports],
|
|
@@ -1465,7 +1473,7 @@ export function createReleasePassport({
|
|
|
1465
1473
|
};
|
|
1466
1474
|
}
|
|
1467
1475
|
|
|
1468
|
-
function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson, productGateJsons, sourceSha, checkedAt }) {
|
|
1476
|
+
function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson, productGateJsons, repository, sourceSha, checkedAt }) {
|
|
1469
1477
|
const manifestMeta = parseJsonInputWithMeta(manifestJson, undefined, { cwd, label: "kfdAdopterManifestJson" });
|
|
1470
1478
|
const supportMatrixMeta = parseJsonInputWithMeta(supportMatrixJson, undefined, { cwd, label: "kfdSupportMatrixJson" });
|
|
1471
1479
|
const productGateMetas = (productGateJsons || [])
|
|
@@ -1476,7 +1484,7 @@ function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson,
|
|
|
1476
1484
|
manifest: manifestMeta.value,
|
|
1477
1485
|
gateResults: productGateMetas.map((meta) => meta.value),
|
|
1478
1486
|
comparisonMatrix: supportMatrixMeta.value,
|
|
1479
|
-
sourceSha,
|
|
1487
|
+
expectedAdopterId: repository || "kungfu-systems/buildchain", expectedSourceRepository: repository, sourceSha,
|
|
1480
1488
|
checkedAt,
|
|
1481
1489
|
});
|
|
1482
1490
|
}
|
|
@@ -1662,7 +1670,7 @@ export function collectGitHubReleasePassport({
|
|
|
1662
1670
|
const productMechanism = defaultProductMechanism({ repository, productName });
|
|
1663
1671
|
const kfdAdopterEvidence = collectKfdAdopterReleaseInputs({
|
|
1664
1672
|
cwd, manifestJson: kfdAdopterManifestJson, supportMatrixJson: kfdSupportMatrixJson,
|
|
1665
|
-
productGateJsons: kfdProductGateJsons, sourceSha, checkedAt: resolvedCheckedAt,
|
|
1673
|
+
productGateJsons: kfdProductGateJsons, repository, sourceSha, checkedAt: resolvedCheckedAt,
|
|
1666
1674
|
});
|
|
1667
1675
|
const {
|
|
1668
1676
|
manifest: kfdAdopterManifest,
|
|
@@ -2094,6 +2102,13 @@ function validateReleaseEvidenceContracts({
|
|
|
2094
2102
|
validateContract(agentIndex, AGENT_INDEX_CONTRACT, "agentIndex", issues);
|
|
2095
2103
|
validateContract(productMechanism, PRODUCT_MECHANISM_CONTRACT, "productMechanism", issues);
|
|
2096
2104
|
validateKfdAgentHubReleaseEvidence(passport?.kfdAgentHub, kfdAgentHubEvidence, issues);
|
|
2105
|
+
for (const entry of validateAdopterDeliveryReleaseEvidence({
|
|
2106
|
+
binding: passport?.adopterDelivery,
|
|
2107
|
+
artifactBinding: artifactEvidence?.adopterDelivery,
|
|
2108
|
+
expectedProjectRepository: optionalString(passport?.product?.repository),
|
|
2109
|
+
})) {
|
|
2110
|
+
issues.push(issue("error", entry.code, entry.message, entry.details));
|
|
2111
|
+
}
|
|
2097
2112
|
for (const entry of validateKfdAdopterReleaseEvidence({
|
|
2098
2113
|
binding: passport?.kfdAdopter,
|
|
2099
2114
|
artifactBinding: artifactEvidence?.kfdAdopter,
|
|
@@ -2101,7 +2116,8 @@ function validateReleaseEvidenceContracts({
|
|
|
2101
2116
|
manifestGate: kfdAdopterManifestGate,
|
|
2102
2117
|
legacyProjection: kfdSupportEvidence,
|
|
2103
2118
|
passportLegacyProjection: passport?.kfdSupport,
|
|
2104
|
-
|
|
2119
|
+
expectedAdopterId: optionalString(passport?.product?.repository) || "kungfu-systems/buildchain",
|
|
2120
|
+
expectedSourceRepository: optionalString(passport?.product?.repository), expectedSourceSha: optionalString(passport?.release?.sourceSha),
|
|
2105
2121
|
})) {
|
|
2106
2122
|
issues.push(issue("error", entry.code, entry.message, entry.details));
|
|
2107
2123
|
}
|
|
@@ -2650,6 +2666,7 @@ function buildReleaseCheckReport({
|
|
|
2650
2666
|
? passport.platformArtifactManifests.length
|
|
2651
2667
|
: 0,
|
|
2652
2668
|
distTagPromotionEvidencePresent: Boolean(passport?.distTagPromotion),
|
|
2669
|
+
adopterDeliveryPresent: Boolean(passport?.adopterDelivery),
|
|
2653
2670
|
impactPresent: Boolean(impact),
|
|
2654
2671
|
agentIndexPresent: Boolean(agentIndex),
|
|
2655
2672
|
productMechanismPresent: Boolean(productMechanism),
|
|
@@ -75,6 +75,103 @@ function qualificationId(value) {
|
|
|
75
75
|
return exact(value, /^mac-(?:smoke-0[12]|full-01)$/, "qualificationId");
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
function terminalFailureRunIds(value) {
|
|
79
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
80
|
+
throw new Error("terminalFailureRunIds must be a non-empty array");
|
|
81
|
+
}
|
|
82
|
+
const normalized = value.map((entry) =>
|
|
83
|
+
exact(entry, /^[1-9]\d*$/, "terminalFailureRunId"),
|
|
84
|
+
);
|
|
85
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
86
|
+
throw new Error("terminalFailureRunIds must be unique");
|
|
87
|
+
}
|
|
88
|
+
return [...normalized].sort((left, right) => Number(left) - Number(right));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function preflightFailureRunIds(value) {
|
|
92
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
93
|
+
throw new Error("preflightFailureRunIds must be a non-empty array");
|
|
94
|
+
}
|
|
95
|
+
const normalized = value.map((entry) =>
|
|
96
|
+
exact(entry, /^[1-9]\d*$/, "preflightFailureRunId"),
|
|
97
|
+
);
|
|
98
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
99
|
+
throw new Error("preflightFailureRunIds must be unique");
|
|
100
|
+
}
|
|
101
|
+
return [...normalized].sort((left, right) => Number(left) - Number(right));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function successfulRunIds(value) {
|
|
105
|
+
if (value === undefined) return [];
|
|
106
|
+
if (!Array.isArray(value)) {
|
|
107
|
+
throw new Error("successfulRunIds must be an array");
|
|
108
|
+
}
|
|
109
|
+
const normalized = value.map((entry) =>
|
|
110
|
+
exact(entry, /^[1-9]\d*$/, "successfulRunId"),
|
|
111
|
+
);
|
|
112
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
113
|
+
throw new Error("successfulRunIds must be unique");
|
|
114
|
+
}
|
|
115
|
+
return [...normalized].sort((left, right) => Number(left) - Number(right));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function startupFailureRuns(value) {
|
|
119
|
+
if (value === undefined) return [];
|
|
120
|
+
if (!Array.isArray(value)) {
|
|
121
|
+
throw new Error("startupFailureRuns must be an array");
|
|
122
|
+
}
|
|
123
|
+
const normalized = value.map((entry) => ({
|
|
124
|
+
runId: exact(entry?.runId, /^[1-9]\d*$/, "startupFailureRunId"),
|
|
125
|
+
sourceSha: exactSha(entry?.sourceSha),
|
|
126
|
+
}));
|
|
127
|
+
if (
|
|
128
|
+
new Set(normalized.map(({ runId }) => runId)).size !== normalized.length
|
|
129
|
+
) {
|
|
130
|
+
throw new Error("startupFailureRuns must use unique run ids");
|
|
131
|
+
}
|
|
132
|
+
return [...normalized].sort(
|
|
133
|
+
(left, right) => Number(left.runId) - Number(right.runId),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function historicalTerminalFailureRuns(value) {
|
|
138
|
+
if (value === undefined) return [];
|
|
139
|
+
if (!Array.isArray(value)) {
|
|
140
|
+
throw new Error("historicalTerminalFailureRuns must be an array");
|
|
141
|
+
}
|
|
142
|
+
const normalized = value.map((entry) => ({
|
|
143
|
+
runId: exact(entry?.runId, /^[1-9]\d*$/, "historicalTerminalFailureRunId"),
|
|
144
|
+
sourceSha: exactSha(entry?.sourceSha),
|
|
145
|
+
}));
|
|
146
|
+
if (
|
|
147
|
+
new Set(normalized.map(({ runId }) => runId)).size !== normalized.length
|
|
148
|
+
) {
|
|
149
|
+
throw new Error("historicalTerminalFailureRuns must use unique run ids");
|
|
150
|
+
}
|
|
151
|
+
return [...normalized].sort(
|
|
152
|
+
(left, right) => Number(left.runId) - Number(right.runId),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function historicalPreflightFailureRuns(value) {
|
|
157
|
+
if (value === undefined) return [];
|
|
158
|
+
if (!Array.isArray(value)) {
|
|
159
|
+
throw new Error("historicalPreflightFailureRuns must be an array");
|
|
160
|
+
}
|
|
161
|
+
const normalized = value.map((entry) => ({
|
|
162
|
+
runId: exact(entry?.runId, /^[1-9]\d*$/, "historicalPreflightFailureRunId"),
|
|
163
|
+
sourceSha: exactSha(entry?.sourceSha),
|
|
164
|
+
}));
|
|
165
|
+
if (
|
|
166
|
+
new Set(normalized.map(({ runId }) => runId)).size !== normalized.length
|
|
167
|
+
) {
|
|
168
|
+
throw new Error("historicalPreflightFailureRuns must use unique run ids");
|
|
169
|
+
}
|
|
170
|
+
return [...normalized].sort(
|
|
171
|
+
(left, right) => Number(left.runId) - Number(right.runId),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
78
175
|
function commonAws(values) {
|
|
79
176
|
const region = exact(
|
|
80
177
|
values.region || MACOS_EC2_JIT.region,
|
|
@@ -203,6 +300,87 @@ export function createMacosJitCampaignPlan(values = {}) {
|
|
|
203
300
|
return { ...plan, digest: digest(plan) };
|
|
204
301
|
}
|
|
205
302
|
|
|
303
|
+
export function createMacosJitInstanceRehydratePlan(values = {}) {
|
|
304
|
+
const id = campaignId(values.campaignId);
|
|
305
|
+
const boundSource = source(values);
|
|
306
|
+
const aws = commonAws(values);
|
|
307
|
+
const regionConfig = macosJitRegionConfig(aws.region);
|
|
308
|
+
const tags = ownershipTags({ id, sourceSha: boundSource.sha });
|
|
309
|
+
const rehydrationId = exact(
|
|
310
|
+
values.rehydrationId,
|
|
311
|
+
/^r[1-9]\d{0,2}$/,
|
|
312
|
+
"rehydrationId",
|
|
313
|
+
);
|
|
314
|
+
const instanceClientToken = `kungfu-mac-rehydrate-${id}-${rehydrationId}`;
|
|
315
|
+
if (instanceClientToken.length > 64) {
|
|
316
|
+
throw new Error("rehydration client token exceeds the EC2 limit");
|
|
317
|
+
}
|
|
318
|
+
const plan = {
|
|
319
|
+
schemaVersion: 1,
|
|
320
|
+
contract: AWS_MACOS_JIT_CONTROLLER_CONTRACT,
|
|
321
|
+
kind: "instance-rehydrate-plan",
|
|
322
|
+
repository: repository(values.repository),
|
|
323
|
+
account: {
|
|
324
|
+
id: exact(values.accountId, /^\d{12}$/, "accountId"),
|
|
325
|
+
},
|
|
326
|
+
github: {
|
|
327
|
+
workflowId: MACOS_EC2_JIT.workflowId,
|
|
328
|
+
requiredState: "disabled_manually",
|
|
329
|
+
},
|
|
330
|
+
campaign: { id },
|
|
331
|
+
source: boundSource,
|
|
332
|
+
aws: {
|
|
333
|
+
...aws,
|
|
334
|
+
hostId: exact(values.hostId, /^h-[0-9a-f]+$/, "hostId"),
|
|
335
|
+
hostAllocatedAt: iso(values.hostAllocatedAt, "hostAllocatedAt"),
|
|
336
|
+
replacesInstanceId: exact(
|
|
337
|
+
values.replacesInstanceId,
|
|
338
|
+
/^i-[0-9a-f]+$/,
|
|
339
|
+
"replacesInstanceId",
|
|
340
|
+
),
|
|
341
|
+
rehydrationId,
|
|
342
|
+
instanceTags: tags,
|
|
343
|
+
volumeTags: tags,
|
|
344
|
+
instanceClientToken,
|
|
345
|
+
rootVolume: {
|
|
346
|
+
deviceName: "/dev/sda1",
|
|
347
|
+
deleteOnTermination: true,
|
|
348
|
+
encrypted: true,
|
|
349
|
+
volumeSizeGiB: 200,
|
|
350
|
+
volumeType: "gp3",
|
|
351
|
+
},
|
|
352
|
+
metadata: {
|
|
353
|
+
httpEndpoint: "enabled",
|
|
354
|
+
httpTokens: "required",
|
|
355
|
+
httpPutResponseHopLimit: 1,
|
|
356
|
+
instanceMetadataTags: "disabled",
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
safety: {
|
|
360
|
+
applyMode: values.execute === true ? "execute" : "dry-run",
|
|
361
|
+
exactSourceRequired: true,
|
|
362
|
+
existingCampaignHostRequired: true,
|
|
363
|
+
noHostAllocation: true,
|
|
364
|
+
zeroActiveInstanceRequired: true,
|
|
365
|
+
zeroRunnerResidueRequired: true,
|
|
366
|
+
awsDryRunRequiredBeforeLaunch: true,
|
|
367
|
+
cleanupOwner: "scheduled-card-scoped-reaper",
|
|
368
|
+
budget: {
|
|
369
|
+
name: regionConfig.budgetName,
|
|
370
|
+
limitUsd: MACOS_EC2_JIT.budgetLimitUsd,
|
|
371
|
+
metrics: ["UnblendedCost"],
|
|
372
|
+
dimensionFilter: {
|
|
373
|
+
usageTypes: regionConfig.budgetUsageTypes,
|
|
374
|
+
operation: MACOS_EC2_JIT.budgetOperation,
|
|
375
|
+
regions: regionConfig.budgetRegions,
|
|
376
|
+
},
|
|
377
|
+
requiredActualThresholds: [80, 95],
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
return { ...plan, digest: digest(plan) };
|
|
382
|
+
}
|
|
383
|
+
|
|
206
384
|
export function createMacosJitSourceRebindPlan(values = {}) {
|
|
207
385
|
const id = campaignId(values.campaignId);
|
|
208
386
|
const boundSource = source(values);
|
|
@@ -219,6 +397,48 @@ export function createMacosJitSourceRebindPlan(values = {}) {
|
|
|
219
397
|
if (workflowId !== MACOS_EC2_JIT.workflowId) {
|
|
220
398
|
throw new Error(`workflowId must be ${MACOS_EC2_JIT.workflowId}`);
|
|
221
399
|
}
|
|
400
|
+
const priorRunPolicy = values.priorRunPolicy || "unused";
|
|
401
|
+
if (
|
|
402
|
+
!["unused", "terminal-failure", "preflight-failure"].includes(
|
|
403
|
+
priorRunPolicy,
|
|
404
|
+
)
|
|
405
|
+
) {
|
|
406
|
+
throw new Error(
|
|
407
|
+
"priorRunPolicy must be unused, terminal-failure, or preflight-failure",
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
const terminalRunIds =
|
|
411
|
+
priorRunPolicy === "terminal-failure"
|
|
412
|
+
? terminalFailureRunIds(values.terminalFailureRunIds)
|
|
413
|
+
: [];
|
|
414
|
+
const preflightRunIds =
|
|
415
|
+
priorRunPolicy === "preflight-failure"
|
|
416
|
+
? preflightFailureRunIds(values.preflightFailureRunIds)
|
|
417
|
+
: [];
|
|
418
|
+
const startupRuns = startupFailureRuns(values.startupFailureRuns);
|
|
419
|
+
const historicalTerminalRuns = historicalTerminalFailureRuns(
|
|
420
|
+
values.historicalTerminalFailureRuns,
|
|
421
|
+
);
|
|
422
|
+
const historicalPreflightRuns = historicalPreflightFailureRuns(
|
|
423
|
+
values.historicalPreflightFailureRuns,
|
|
424
|
+
);
|
|
425
|
+
const successfulRuns = successfulRunIds(values.successfulRunIds);
|
|
426
|
+
if (priorRunPolicy === "unused" && startupRuns.length !== 0) {
|
|
427
|
+
throw new Error("startupFailureRuns require a failed priorRunPolicy");
|
|
428
|
+
}
|
|
429
|
+
if (priorRunPolicy === "unused" && historicalTerminalRuns.length !== 0) {
|
|
430
|
+
throw new Error(
|
|
431
|
+
"historicalTerminalFailureRuns require a failed priorRunPolicy",
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
if (priorRunPolicy === "unused" && historicalPreflightRuns.length !== 0) {
|
|
435
|
+
throw new Error(
|
|
436
|
+
"historicalPreflightFailureRuns require a failed priorRunPolicy",
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
if (priorRunPolicy === "unused" && successfulRuns.length !== 0) {
|
|
440
|
+
throw new Error("successfulRunIds require a failed priorRunPolicy");
|
|
441
|
+
}
|
|
222
442
|
const plan = {
|
|
223
443
|
schemaVersion: 1,
|
|
224
444
|
contract: AWS_MACOS_JIT_CONTROLLER_CONTRACT,
|
|
@@ -233,6 +453,13 @@ export function createMacosJitSourceRebindPlan(values = {}) {
|
|
|
233
453
|
github: {
|
|
234
454
|
workflowId,
|
|
235
455
|
requiredState: "disabled_manually",
|
|
456
|
+
priorRunPolicy,
|
|
457
|
+
terminalFailureRunIds: terminalRunIds,
|
|
458
|
+
preflightFailureRunIds: preflightRunIds,
|
|
459
|
+
startupFailureRuns: startupRuns,
|
|
460
|
+
historicalTerminalFailureRuns: historicalTerminalRuns,
|
|
461
|
+
historicalPreflightFailureRuns: historicalPreflightRuns,
|
|
462
|
+
successfulRunIds: successfulRuns,
|
|
236
463
|
},
|
|
237
464
|
aws: {
|
|
238
465
|
...aws,
|
|
@@ -246,8 +473,16 @@ export function createMacosJitSourceRebindPlan(values = {}) {
|
|
|
246
473
|
forwardOnlySource: true,
|
|
247
474
|
sameSourceRefRequired: true,
|
|
248
475
|
workflowDisabledRequired: true,
|
|
249
|
-
zeroPriorJobsRequired:
|
|
250
|
-
zeroPriorArtifactsRequired:
|
|
476
|
+
zeroPriorJobsRequired: priorRunPolicy === "unused",
|
|
477
|
+
zeroPriorArtifactsRequired: priorRunPolicy === "unused",
|
|
478
|
+
terminalFailureEvidencePreserved: priorRunPolicy === "terminal-failure",
|
|
479
|
+
preflightFailureEvidencePreserved: priorRunPolicy === "preflight-failure",
|
|
480
|
+
startupFailureEvidencePreserved: startupRuns.length !== 0,
|
|
481
|
+
historicalTerminalFailureEvidencePreserved:
|
|
482
|
+
historicalTerminalRuns.length !== 0,
|
|
483
|
+
historicalPreflightFailureEvidencePreserved:
|
|
484
|
+
historicalPreflightRuns.length !== 0,
|
|
485
|
+
successfulRunEvidencePreserved: successfulRuns.length !== 0,
|
|
251
486
|
zeroJitResidueRequired: true,
|
|
252
487
|
zeroEvidenceRequired: true,
|
|
253
488
|
exactCampaignResourcesRequired: true,
|
|
@@ -301,9 +536,9 @@ export function macosAllocateHostsArgs(plan) {
|
|
|
301
536
|
export function macosRunInstancesArgs(plan, { hostId, dryRun = false } = {}) {
|
|
302
537
|
if (
|
|
303
538
|
plan?.contract !== AWS_MACOS_JIT_CONTROLLER_CONTRACT ||
|
|
304
|
-
|
|
539
|
+
!["campaign-launch-plan", "instance-rehydrate-plan"].includes(plan.kind)
|
|
305
540
|
) {
|
|
306
|
-
throw new Error("macOS JIT
|
|
541
|
+
throw new Error("macOS JIT instance launch plan contract is invalid");
|
|
307
542
|
}
|
|
308
543
|
const resolvedHostId = exact(hostId, /^h-[0-9a-f]+$/, "hostId");
|
|
309
544
|
const args = [
|