@kungfu-tech/buildchain 3.0.5-alpha.7 → 3.0.5
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 +0 -31
- package/actions/macos-credential-island/README.md +0 -8
- package/bin/buildchain.mjs +1 -1
- package/contracts/auditable-demo-media-profiles-v1.json +0 -61
- package/contracts/evidence/auditable-demo-responsive-web-delivery-v1.json +3 -3
- package/contracts/evidence/auditable-demo-web-delivery-v1.json +3 -3
- package/dist/site/buildchain-contract.json +25 -86
- package/dist/site/buildchain-site.json +38 -64
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/cli-registry.json +2 -6
- package/dist/site/controller-registry.json +3 -11
- package/dist/site/kfd-claims.json +11 -53
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +7 -7
- package/dist/site/node-api-registry.json +31 -213
- package/dist/site/page-registry.json +20 -50
- package/dist/site/public-surface-audit.json +8 -98
- package/dist/site/publication-authority-registry.json +1 -42
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +11 -11
- package/dist/site/workflow-registry.json +2 -67
- package/docs/auditable-demo.md +7 -74
- package/docs/aws-us-elastic-runner-burst-plane.md +16 -151
- package/docs/cli-reference.md +2 -24
- package/docs/node-api-reference.md +72 -90
- package/docs/publish-transaction.md +5 -7
- package/docs/release-flow.md +0 -4
- package/docs/release-governance.md +0 -39
- package/docs/reusable-build-surface.md +0 -9
- package/package.json +1 -1
- package/packages/core/buildchain-contract.js +1 -36
- package/packages/core/buildchain-publication-authority.js +0 -2
- package/packages/core/public-surface-audit.js +35 -4
- package/packages/core/release-propagation-release.js +18 -61
- package/packages/core/release-propagation-work.js +3 -7
- package/packages/core/release-propagation.js +2 -12
- package/scripts/auditable-demo-renditions.mjs +2 -7
- package/scripts/auditable-demo.mjs +21 -27
- package/scripts/aws-windows-jit-controller-core.mjs +2 -20
- package/scripts/aws-windows-jit-controller.mjs +109 -184
- package/scripts/aws-windows-jit-core.mjs +3 -21
- package/scripts/aws-windows-jit.mjs +0 -2
- package/scripts/build-standalone-binary.mjs +0 -4
- package/scripts/buildchain-cli-help.mjs +1 -2
- package/scripts/capture-package-release-propagation.mjs +1 -24
- package/scripts/check-inventory.mjs +0 -5
- package/scripts/finalize-native-artifact-signing-result.mjs +15 -37
- package/scripts/generate-site-bundle.mjs +0 -2
- package/scripts/locked-source-checkout.mjs +3 -17
- package/scripts/release-propagation.mjs +2 -77
- package/contracts/auditable-demo-scenario-v1.schema.json +0 -153
- package/packages/core/release-propagation-pickup.js +0 -386
- package/packages/core/workflow-call-contract.js +0 -308
- package/packages/core/workflow-yaml-contract.js +0 -272
- package/scripts/auditable-demo-platform.mjs +0 -506
- package/scripts/aws-macos-jit-controller-core.mjs +0 -389
- package/scripts/aws-macos-jit-controller-runtime.mjs +0 -82
- package/scripts/aws-macos-jit-controller.mjs +0 -558
- package/scripts/aws-macos-jit-job-controller.mjs +0 -401
- package/scripts/aws-windows-jit-campaign-core.mjs +0 -296
- package/scripts/aws-windows-jit-campaign.mjs +0 -202
- package/scripts/workflow-call-contract.mjs +0 -133
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
import { digest } from "./aws-runner-burst-core.mjs";
|
|
4
4
|
import {
|
|
5
5
|
WINDOWS_EC2_JIT,
|
|
6
|
-
windowsJitCampaignId,
|
|
7
6
|
windowsJitRunnerLabel,
|
|
8
7
|
windowsJitRunnerLabels,
|
|
9
8
|
} from "./aws-windows-jit-core.mjs";
|
|
10
9
|
|
|
11
10
|
export const AWS_WINDOWS_JIT_CONTROLLER_CONTRACT =
|
|
12
|
-
"kungfu-buildchain-aws-windows-jit-controller/
|
|
11
|
+
"kungfu-buildchain-aws-windows-jit-controller/v1";
|
|
13
12
|
|
|
14
13
|
function exact(value, pattern, label) {
|
|
15
14
|
const normalized = String(value || "").trim();
|
|
@@ -60,9 +59,8 @@ export function createWindowsJitLaunchPlan(values = {}) {
|
|
|
60
59
|
);
|
|
61
60
|
const jobId = exact(values.jobId, /^\d+$/, "jobId");
|
|
62
61
|
const qualification = qualificationId(values.qualificationId);
|
|
63
|
-
const campaign = windowsJitCampaignId(values.campaignId);
|
|
64
62
|
const runnerLabel = windowsJitRunnerLabel(values.runnerLabel);
|
|
65
|
-
const expectedLabel = `${WINDOWS_EC2_JIT.labelPrefix}${
|
|
63
|
+
const expectedLabel = `${WINDOWS_EC2_JIT.labelPrefix}${qualification}`;
|
|
66
64
|
if (runnerLabel !== expectedLabel) {
|
|
67
65
|
throw new Error(`runnerLabel must be ${expectedLabel}`);
|
|
68
66
|
}
|
|
@@ -111,11 +109,6 @@ export function createWindowsJitLaunchPlan(values = {}) {
|
|
|
111
109
|
/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/,
|
|
112
110
|
"evidenceBucket",
|
|
113
111
|
);
|
|
114
|
-
const stateTable = exact(
|
|
115
|
-
values.stateTable,
|
|
116
|
-
/^kungfu-buildchain-windows-jit(?:-[A-Za-z0-9_.-]+)?$/,
|
|
117
|
-
"stateTable",
|
|
118
|
-
);
|
|
119
112
|
const launchedAt = iso(values.launchedAt, "launchedAt");
|
|
120
113
|
const clientToken = `kungfu-${runId}-${runAttempt}-${qualification}`;
|
|
121
114
|
const jitParameterName =
|
|
@@ -132,7 +125,6 @@ export function createWindowsJitLaunchPlan(values = {}) {
|
|
|
132
125
|
tag("kungfu:owner", "buildchain"),
|
|
133
126
|
tag("kungfu:plane", "aws-us-elastic-runner-burst"),
|
|
134
127
|
tag("kungfu:provider", "windows-ec2-jit"),
|
|
135
|
-
tag("kungfu:campaign-id", campaign),
|
|
136
128
|
tag("kungfu:github-run-id", runId),
|
|
137
129
|
tag("kungfu:github-run-attempt", runAttempt),
|
|
138
130
|
tag("kungfu:qualification-id", qualification),
|
|
@@ -149,7 +141,6 @@ export function createWindowsJitLaunchPlan(values = {}) {
|
|
|
149
141
|
contract: AWS_WINDOWS_JIT_CONTROLLER_CONTRACT,
|
|
150
142
|
kind: "launch-plan",
|
|
151
143
|
repository,
|
|
152
|
-
campaign: { id: campaign },
|
|
153
144
|
source: { sha: sourceSha, ref: sourceRef },
|
|
154
145
|
github: {
|
|
155
146
|
runId,
|
|
@@ -157,7 +148,6 @@ export function createWindowsJitLaunchPlan(values = {}) {
|
|
|
157
148
|
jobId,
|
|
158
149
|
qualificationId: qualification,
|
|
159
150
|
event: "workflow_dispatch",
|
|
160
|
-
displayTitle: `AWS Windows JIT ${campaign} ${qualification}`,
|
|
161
151
|
},
|
|
162
152
|
runner: {
|
|
163
153
|
name: runnerName,
|
|
@@ -174,7 +164,6 @@ export function createWindowsJitLaunchPlan(values = {}) {
|
|
|
174
164
|
securityGroupId,
|
|
175
165
|
instanceProfileName,
|
|
176
166
|
evidenceBucket,
|
|
177
|
-
stateTable,
|
|
178
167
|
jitParameterName,
|
|
179
168
|
launchedAt,
|
|
180
169
|
clientToken,
|
|
@@ -199,13 +188,6 @@ export function createWindowsJitLaunchPlan(values = {}) {
|
|
|
199
188
|
exactSourceRequired: true,
|
|
200
189
|
queuedJobRequired: true,
|
|
201
190
|
activeInstanceCeiling: WINDOWS_EC2_JIT.maxConcurrentInstances,
|
|
202
|
-
campaignAcceptedInstanceCeiling: WINDOWS_EC2_JIT.maxAcceptedInstances,
|
|
203
|
-
campaignReservationUsd:
|
|
204
|
-
(WINDOWS_EC2_JIT.pricePerHourUsd *
|
|
205
|
-
WINDOWS_EC2_JIT.maximumInstanceLifetimeMinutes) /
|
|
206
|
-
60,
|
|
207
|
-
campaignBudgetLimitUsd: WINDOWS_EC2_JIT.budgetLimitUsd,
|
|
208
|
-
persistentCampaignLedgerRequired: true,
|
|
209
191
|
awsDryRunRequiredBeforeLaunch: true,
|
|
210
192
|
userDataTransport: "fileb://rendered-bootstrap",
|
|
211
193
|
jitConfigTransport: "0600-temporary-file-to-ssm-secure-string",
|
|
@@ -11,10 +11,6 @@ import {
|
|
|
11
11
|
createWindowsJitLaunchPlan,
|
|
12
12
|
windowsRunInstancesArgs,
|
|
13
13
|
} from "./aws-windows-jit-controller-core.mjs";
|
|
14
|
-
import {
|
|
15
|
-
windowsCampaignMarkLaunchedArgs,
|
|
16
|
-
windowsCampaignReservationItems,
|
|
17
|
-
} from "./aws-windows-jit-campaign-core.mjs";
|
|
18
14
|
import { renderWindowsJitBootstrap } from "./aws-windows-jit-core.mjs";
|
|
19
15
|
|
|
20
16
|
function arg(name, fallback = "") {
|
|
@@ -79,7 +75,6 @@ function assertLivePreflight(plan, profile) {
|
|
|
79
75
|
);
|
|
80
76
|
if (
|
|
81
77
|
run.event !== plan.github.event ||
|
|
82
|
-
run.display_title !== plan.github.displayTitle ||
|
|
83
78
|
run.head_sha !== plan.source.sha ||
|
|
84
79
|
run.head_repository?.full_name !== plan.repository ||
|
|
85
80
|
!["queued", "in_progress"].includes(run.status)
|
|
@@ -272,169 +267,6 @@ function cleanupFailedLaunch(
|
|
|
272
267
|
return failures;
|
|
273
268
|
}
|
|
274
269
|
|
|
275
|
-
function generateJitConfiguration(plan) {
|
|
276
|
-
const jit = ghJson(
|
|
277
|
-
[
|
|
278
|
-
"api",
|
|
279
|
-
"--method",
|
|
280
|
-
"POST",
|
|
281
|
-
`repos/${plan.repository}/actions/runners/generate-jitconfig`,
|
|
282
|
-
"--input",
|
|
283
|
-
"-",
|
|
284
|
-
],
|
|
285
|
-
JSON.stringify({
|
|
286
|
-
name: plan.runner.name,
|
|
287
|
-
runner_group_id: 1,
|
|
288
|
-
labels: plan.runner.labels,
|
|
289
|
-
work_folder: "_work",
|
|
290
|
-
}),
|
|
291
|
-
"GitHub JIT configuration",
|
|
292
|
-
).encoded_jit_config;
|
|
293
|
-
if (!jit || typeof jit !== "string") {
|
|
294
|
-
throw new Error("GitHub JIT configuration was empty");
|
|
295
|
-
}
|
|
296
|
-
return jit;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function createJitParameter(plan, profile, parameterInputPath, jit) {
|
|
300
|
-
fs.writeFileSync(
|
|
301
|
-
parameterInputPath,
|
|
302
|
-
JSON.stringify({
|
|
303
|
-
Name: plan.aws.jitParameterName,
|
|
304
|
-
Description: `One-shot GitHub Actions JIT config for ${plan.repository} run ${plan.github.runId} attempt ${plan.github.runAttempt}`,
|
|
305
|
-
Type: "SecureString",
|
|
306
|
-
Tier: "Advanced",
|
|
307
|
-
Value: jit,
|
|
308
|
-
Tags: [
|
|
309
|
-
{ Key: "kungfu:owner", Value: "buildchain" },
|
|
310
|
-
{ Key: "kungfu:plane", Value: "aws-us-elastic-runner-burst" },
|
|
311
|
-
{ Key: "kungfu:provider", Value: "windows-ec2-jit" },
|
|
312
|
-
{ Key: "kungfu:campaign-id", Value: plan.campaign.id },
|
|
313
|
-
{ Key: "kungfu:github-run-id", Value: plan.github.runId },
|
|
314
|
-
{
|
|
315
|
-
Key: "kungfu:qualification-id",
|
|
316
|
-
Value: plan.github.qualificationId,
|
|
317
|
-
},
|
|
318
|
-
],
|
|
319
|
-
}),
|
|
320
|
-
{ mode: 0o600 },
|
|
321
|
-
);
|
|
322
|
-
requireSuccess(
|
|
323
|
-
commandResult(
|
|
324
|
-
"aws",
|
|
325
|
-
awsArgs(plan, profile, [
|
|
326
|
-
"ssm",
|
|
327
|
-
"put-parameter",
|
|
328
|
-
"--cli-input-json",
|
|
329
|
-
`file://${parameterInputPath}`,
|
|
330
|
-
"--output",
|
|
331
|
-
"json",
|
|
332
|
-
]),
|
|
333
|
-
),
|
|
334
|
-
"SSM JIT parameter creation",
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function writeBootstrap(plan, bootstrapPath) {
|
|
339
|
-
const template = fs.readFileSync(
|
|
340
|
-
path.resolve(
|
|
341
|
-
"infra/aws-us-elastic-runner-burst-plane/windows-jit-bootstrap.ps1",
|
|
342
|
-
),
|
|
343
|
-
"utf8",
|
|
344
|
-
);
|
|
345
|
-
fs.writeFileSync(
|
|
346
|
-
bootstrapPath,
|
|
347
|
-
renderWindowsJitBootstrap(template, {
|
|
348
|
-
region: plan.aws.region,
|
|
349
|
-
campaignId: plan.campaign.id,
|
|
350
|
-
jitParameterName: plan.aws.jitParameterName,
|
|
351
|
-
evidenceBucket: plan.aws.evidenceBucket,
|
|
352
|
-
runnerLabel: plan.runner.label,
|
|
353
|
-
sourceSha: plan.source.sha,
|
|
354
|
-
githubRunId: plan.github.runId,
|
|
355
|
-
githubRunAttempt: plan.github.runAttempt,
|
|
356
|
-
amiId: plan.aws.amiId,
|
|
357
|
-
amiName: plan.aws.amiName,
|
|
358
|
-
instanceType: plan.aws.instanceType,
|
|
359
|
-
launchedAt: plan.aws.launchedAt,
|
|
360
|
-
}),
|
|
361
|
-
{ mode: 0o600 },
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function assertLaunchDryRun(plan, profile, bootstrapPath) {
|
|
366
|
-
const dryRun = commandResult(
|
|
367
|
-
"aws",
|
|
368
|
-
awsArgs(
|
|
369
|
-
plan,
|
|
370
|
-
profile,
|
|
371
|
-
windowsRunInstancesArgs(plan, { bootstrapPath, dryRun: true }),
|
|
372
|
-
),
|
|
373
|
-
);
|
|
374
|
-
if (
|
|
375
|
-
dryRun.status === 0 ||
|
|
376
|
-
!/DryRunOperation/.test(`${dryRun.stdout}\n${dryRun.stderr}`)
|
|
377
|
-
) {
|
|
378
|
-
throw new Error("EC2 RunInstances DryRun did not return DryRunOperation");
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function reserveCampaign(plan, profile) {
|
|
383
|
-
requireSuccess(
|
|
384
|
-
commandResult(
|
|
385
|
-
"aws",
|
|
386
|
-
awsArgs(plan, profile, [
|
|
387
|
-
"dynamodb",
|
|
388
|
-
"transact-write-items",
|
|
389
|
-
"--transact-items",
|
|
390
|
-
JSON.stringify(
|
|
391
|
-
windowsCampaignReservationItems(plan, new Date().toISOString()),
|
|
392
|
-
),
|
|
393
|
-
"--output",
|
|
394
|
-
"json",
|
|
395
|
-
]),
|
|
396
|
-
),
|
|
397
|
-
"Windows campaign atomic reservation",
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function launchInstance(plan, profile, bootstrapPath) {
|
|
402
|
-
const launched = jsonResult(
|
|
403
|
-
commandResult(
|
|
404
|
-
"aws",
|
|
405
|
-
awsArgs(
|
|
406
|
-
plan,
|
|
407
|
-
profile,
|
|
408
|
-
windowsRunInstancesArgs(plan, { bootstrapPath, dryRun: false }),
|
|
409
|
-
),
|
|
410
|
-
),
|
|
411
|
-
"EC2 RunInstances",
|
|
412
|
-
);
|
|
413
|
-
const instance = launched.Instances?.[0];
|
|
414
|
-
if (!/^i-[0-9a-f]+$/.test(String(instance?.InstanceId || ""))) {
|
|
415
|
-
throw new Error("EC2 RunInstances returned no instance identity");
|
|
416
|
-
}
|
|
417
|
-
return instance;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function markCampaignLaunched(plan, profile, instanceId) {
|
|
421
|
-
requireSuccess(
|
|
422
|
-
commandResult(
|
|
423
|
-
"aws",
|
|
424
|
-
awsArgs(
|
|
425
|
-
plan,
|
|
426
|
-
profile,
|
|
427
|
-
windowsCampaignMarkLaunchedArgs(
|
|
428
|
-
plan,
|
|
429
|
-
instanceId,
|
|
430
|
-
new Date().toISOString(),
|
|
431
|
-
),
|
|
432
|
-
),
|
|
433
|
-
),
|
|
434
|
-
"Windows campaign launch ledger update",
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
270
|
export function executeWindowsJitLaunch(plan, { profile = "" } = {}) {
|
|
439
271
|
if (plan?.contract !== AWS_WINDOWS_JIT_CONTROLLER_CONTRACT) {
|
|
440
272
|
throw new Error("Windows JIT launch plan contract is invalid");
|
|
@@ -453,23 +285,124 @@ export function executeWindowsJitLaunch(plan, { profile = "" } = {}) {
|
|
|
453
285
|
let failure;
|
|
454
286
|
const cleanupFailures = [];
|
|
455
287
|
try {
|
|
456
|
-
const jit =
|
|
457
|
-
|
|
288
|
+
const jit = ghJson(
|
|
289
|
+
[
|
|
290
|
+
"api",
|
|
291
|
+
"--method",
|
|
292
|
+
"POST",
|
|
293
|
+
`repos/${plan.repository}/actions/runners/generate-jitconfig`,
|
|
294
|
+
"--input",
|
|
295
|
+
"-",
|
|
296
|
+
],
|
|
297
|
+
JSON.stringify({
|
|
298
|
+
name: plan.runner.name,
|
|
299
|
+
runner_group_id: 1,
|
|
300
|
+
labels: plan.runner.labels,
|
|
301
|
+
work_folder: "_work",
|
|
302
|
+
}),
|
|
303
|
+
"GitHub JIT configuration",
|
|
304
|
+
).encoded_jit_config;
|
|
305
|
+
if (!jit || typeof jit !== "string") {
|
|
306
|
+
throw new Error("GitHub JIT configuration was empty");
|
|
307
|
+
}
|
|
308
|
+
fs.writeFileSync(
|
|
309
|
+
parameterInputPath,
|
|
310
|
+
JSON.stringify({
|
|
311
|
+
Name: plan.aws.jitParameterName,
|
|
312
|
+
Description: `One-shot GitHub Actions JIT config for ${plan.repository} run ${plan.github.runId} attempt ${plan.github.runAttempt}`,
|
|
313
|
+
Type: "SecureString",
|
|
314
|
+
Tier: "Advanced",
|
|
315
|
+
Value: jit,
|
|
316
|
+
Tags: [
|
|
317
|
+
{ Key: "kungfu:owner", Value: "buildchain" },
|
|
318
|
+
{ Key: "kungfu:plane", Value: "aws-us-elastic-runner-burst" },
|
|
319
|
+
{ Key: "kungfu:provider", Value: "windows-ec2-jit" },
|
|
320
|
+
{ Key: "kungfu:github-run-id", Value: plan.github.runId },
|
|
321
|
+
{
|
|
322
|
+
Key: "kungfu:qualification-id",
|
|
323
|
+
Value: plan.github.qualificationId,
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
}),
|
|
327
|
+
{ mode: 0o600 },
|
|
328
|
+
);
|
|
329
|
+
requireSuccess(
|
|
330
|
+
commandResult(
|
|
331
|
+
"aws",
|
|
332
|
+
awsArgs(plan, profile, [
|
|
333
|
+
"ssm",
|
|
334
|
+
"put-parameter",
|
|
335
|
+
"--cli-input-json",
|
|
336
|
+
`file://${parameterInputPath}`,
|
|
337
|
+
"--output",
|
|
338
|
+
"json",
|
|
339
|
+
]),
|
|
340
|
+
),
|
|
341
|
+
"SSM JIT parameter creation",
|
|
342
|
+
);
|
|
458
343
|
parameterCreated = true;
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
344
|
+
fs.writeFileSync(
|
|
345
|
+
bootstrapPath,
|
|
346
|
+
renderWindowsJitBootstrap(
|
|
347
|
+
fs.readFileSync(
|
|
348
|
+
path.resolve(
|
|
349
|
+
"infra/aws-us-elastic-runner-burst-plane/windows-jit-bootstrap.ps1",
|
|
350
|
+
),
|
|
351
|
+
"utf8",
|
|
352
|
+
),
|
|
353
|
+
{
|
|
354
|
+
region: plan.aws.region,
|
|
355
|
+
jitParameterName: plan.aws.jitParameterName,
|
|
356
|
+
evidenceBucket: plan.aws.evidenceBucket,
|
|
357
|
+
runnerLabel: plan.runner.label,
|
|
358
|
+
sourceSha: plan.source.sha,
|
|
359
|
+
githubRunId: plan.github.runId,
|
|
360
|
+
githubRunAttempt: plan.github.runAttempt,
|
|
361
|
+
amiId: plan.aws.amiId,
|
|
362
|
+
amiName: plan.aws.amiName,
|
|
363
|
+
instanceType: plan.aws.instanceType,
|
|
364
|
+
launchedAt: plan.aws.launchedAt,
|
|
365
|
+
},
|
|
366
|
+
),
|
|
367
|
+
{ mode: 0o600 },
|
|
368
|
+
);
|
|
369
|
+
const dryRun = commandResult(
|
|
370
|
+
"aws",
|
|
371
|
+
awsArgs(
|
|
372
|
+
plan,
|
|
373
|
+
profile,
|
|
374
|
+
windowsRunInstancesArgs(plan, { bootstrapPath, dryRun: true }),
|
|
375
|
+
),
|
|
376
|
+
);
|
|
377
|
+
if (
|
|
378
|
+
dryRun.status === 0 ||
|
|
379
|
+
!/DryRunOperation/.test(`${dryRun.stdout}\n${dryRun.stderr}`)
|
|
380
|
+
) {
|
|
381
|
+
throw new Error("EC2 RunInstances DryRun did not return DryRunOperation");
|
|
382
|
+
}
|
|
462
383
|
launchAttempted = true;
|
|
463
|
-
const
|
|
384
|
+
const launched = jsonResult(
|
|
385
|
+
commandResult(
|
|
386
|
+
"aws",
|
|
387
|
+
awsArgs(
|
|
388
|
+
plan,
|
|
389
|
+
profile,
|
|
390
|
+
windowsRunInstancesArgs(plan, { bootstrapPath, dryRun: false }),
|
|
391
|
+
),
|
|
392
|
+
),
|
|
393
|
+
"EC2 RunInstances",
|
|
394
|
+
);
|
|
395
|
+
const instance = launched.Instances?.[0];
|
|
396
|
+
if (!/^i-[0-9a-f]+$/.test(String(instance?.InstanceId || ""))) {
|
|
397
|
+
throw new Error("EC2 RunInstances returned no instance identity");
|
|
398
|
+
}
|
|
464
399
|
launchSucceeded = true;
|
|
465
|
-
markCampaignLaunched(plan, profile, instance.InstanceId);
|
|
466
400
|
result = {
|
|
467
401
|
schemaVersion: 1,
|
|
468
402
|
contract: AWS_WINDOWS_JIT_CONTROLLER_CONTRACT,
|
|
469
403
|
kind: "launch-result",
|
|
470
404
|
status: "launched",
|
|
471
405
|
source: plan.source,
|
|
472
|
-
campaign: plan.campaign,
|
|
473
406
|
github: plan.github,
|
|
474
407
|
runner: plan.runner,
|
|
475
408
|
aws: {
|
|
@@ -519,7 +452,6 @@ function planFromArgs(execute) {
|
|
|
519
452
|
runAttempt: arg("run-attempt", "1"),
|
|
520
453
|
jobId: arg("job-id"),
|
|
521
454
|
qualificationId: arg("qualification-id"),
|
|
522
|
-
campaignId: arg("campaign-id"),
|
|
523
455
|
runnerLabel: arg("runner-label"),
|
|
524
456
|
runnerName: arg("runner-name"),
|
|
525
457
|
sourceSha: arg("source-sha"),
|
|
@@ -532,7 +464,6 @@ function planFromArgs(execute) {
|
|
|
532
464
|
securityGroupId: arg("security-group-id"),
|
|
533
465
|
instanceProfileName: arg("instance-profile-name"),
|
|
534
466
|
evidenceBucket: arg("evidence-bucket"),
|
|
535
|
-
stateTable: arg("state-table"),
|
|
536
467
|
jitParameterName: arg("jit-parameter"),
|
|
537
468
|
launchedAt: arg("launched-at", new Date().toISOString()),
|
|
538
469
|
});
|
|
@@ -551,12 +482,6 @@ export function main() {
|
|
|
551
482
|
if (arg("confirm-run-id") !== plan.github.runId) {
|
|
552
483
|
throw new Error("--confirm-run-id must equal the exact GitHub run id");
|
|
553
484
|
}
|
|
554
|
-
if (arg("confirm-campaign-id") !== plan.campaign.id) {
|
|
555
|
-
throw new Error("--confirm-campaign-id must equal the campaign id");
|
|
556
|
-
}
|
|
557
|
-
if (arg("confirm-state-table") !== plan.aws.stateTable) {
|
|
558
|
-
throw new Error("--confirm-state-table must equal the campaign state table");
|
|
559
|
-
}
|
|
560
485
|
const result = executeWindowsJitLaunch(plan, {
|
|
561
486
|
profile: arg("aws-profile"),
|
|
562
487
|
});
|
|
@@ -10,9 +10,9 @@ export const WINDOWS_EC2_JIT = Object.freeze({
|
|
|
10
10
|
instanceType: "c7i.4xlarge",
|
|
11
11
|
pricePerHourUsd: 1.45,
|
|
12
12
|
maximumInstanceLifetimeMinutes: 180,
|
|
13
|
-
maxConcurrentInstances:
|
|
14
|
-
maxAcceptedInstances:
|
|
15
|
-
budgetLimitUsd:
|
|
13
|
+
maxConcurrentInstances: 2,
|
|
14
|
+
maxAcceptedInstances: 6,
|
|
15
|
+
budgetLimitUsd: 40,
|
|
16
16
|
minimumSmokeJobs: 1,
|
|
17
17
|
minimumFullJobs: 3,
|
|
18
18
|
maximumCleanupLatencySeconds: 900,
|
|
@@ -75,14 +75,6 @@ export function windowsJitRunnerLabels(value) {
|
|
|
75
75
|
return ["self-hosted", "Windows", "X64", windowsJitRunnerLabel(value)];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
export function windowsJitCampaignId(value) {
|
|
79
|
-
const campaign = String(value || "").trim();
|
|
80
|
-
if (!/^win-[a-z0-9][a-z0-9-]{2,15}$/.test(campaign)) {
|
|
81
|
-
throw new Error("campaignId must be a bounded Windows campaign id");
|
|
82
|
-
}
|
|
83
|
-
return campaign;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
78
|
export function renderWindowsJitBootstrap(template, values = {}) {
|
|
87
79
|
const runnerLabel = windowsJitRunnerLabel(values.runnerLabel);
|
|
88
80
|
const jitParameterName = String(values.jitParameterName || "").trim();
|
|
@@ -94,7 +86,6 @@ export function renderWindowsJitBootstrap(template, values = {}) {
|
|
|
94
86
|
}
|
|
95
87
|
const bounded = {
|
|
96
88
|
REGION: String(values.region || WINDOWS_EC2_JIT.region),
|
|
97
|
-
CAMPAIGN_ID: String(values.campaignId || ""),
|
|
98
89
|
JIT_PARAMETER_NAME: jitParameterName,
|
|
99
90
|
EVIDENCE_BUCKET: String(values.evidenceBucket || ""),
|
|
100
91
|
RUNNER_LABEL: runnerLabel,
|
|
@@ -108,7 +99,6 @@ export function renderWindowsJitBootstrap(template, values = {}) {
|
|
|
108
99
|
};
|
|
109
100
|
const patterns = {
|
|
110
101
|
REGION: /^us-[a-z]+-\d$/,
|
|
111
|
-
CAMPAIGN_ID: /^win-[a-z0-9][a-z0-9-]{2,43}$/,
|
|
112
102
|
EVIDENCE_BUCKET: /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/,
|
|
113
103
|
GITHUB_RUN_ID: /^\d+$/,
|
|
114
104
|
GITHUB_RUN_ATTEMPT: /^\d+$/,
|
|
@@ -194,7 +184,6 @@ export function windowsEc2JitPlan(overrides = {}) {
|
|
|
194
184
|
|
|
195
185
|
export function createWindowsJitEvidence({
|
|
196
186
|
repository,
|
|
197
|
-
campaignId,
|
|
198
187
|
sourceSha,
|
|
199
188
|
sourceRef,
|
|
200
189
|
githubRunId,
|
|
@@ -246,7 +235,6 @@ export function createWindowsJitEvidence({
|
|
|
246
235
|
phase: WINDOWS_EC2_JIT.phase,
|
|
247
236
|
provider: "aws-ec2",
|
|
248
237
|
repository,
|
|
249
|
-
campaign: { id: windowsJitCampaignId(campaignId) },
|
|
250
238
|
source: {
|
|
251
239
|
sha: exactSha(sourceSha, "sourceSha"),
|
|
252
240
|
ref: String(sourceRef || "").trim(),
|
|
@@ -298,7 +286,6 @@ export function createWindowsJitEvidence({
|
|
|
298
286
|
}
|
|
299
287
|
|
|
300
288
|
export function verifyWindowsEc2JitQualification({
|
|
301
|
-
campaignId,
|
|
302
289
|
jobs = [],
|
|
303
290
|
cancellationCleanup = {},
|
|
304
291
|
timeoutCleanup = {},
|
|
@@ -312,7 +299,6 @@ export function verifyWindowsEc2JitQualification({
|
|
|
312
299
|
} = {}) {
|
|
313
300
|
const plan = windowsEc2JitPlan();
|
|
314
301
|
const issues = [];
|
|
315
|
-
const campaign = windowsJitCampaignId(campaignId);
|
|
316
302
|
const accepted = jobs.filter(
|
|
317
303
|
(job) =>
|
|
318
304
|
job?.trusted === true &&
|
|
@@ -322,9 +308,6 @@ export function verifyWindowsEc2JitQualification({
|
|
|
322
308
|
);
|
|
323
309
|
const smokeJobs = accepted.filter((job) => job.kind === "smoke");
|
|
324
310
|
const fullJobs = accepted.filter((job) => job.kind === "full");
|
|
325
|
-
if (accepted.some((job) => job.campaignId !== campaign)) {
|
|
326
|
-
issues.push("accepted-jobs-not-bound-to-campaign");
|
|
327
|
-
}
|
|
328
311
|
if (smokeJobs.length < plan.config.minimumSmokeJobs) {
|
|
329
312
|
issues.push("runner-profile-smoke-missing");
|
|
330
313
|
}
|
|
@@ -366,7 +349,6 @@ export function verifyWindowsEc2JitQualification({
|
|
|
366
349
|
contract: AWS_WINDOWS_JIT_CONTRACT,
|
|
367
350
|
kind: "phase-verification",
|
|
368
351
|
phase: plan.config.phase,
|
|
369
|
-
campaign: { id: campaign },
|
|
370
352
|
status: issues.length ? "failed" : "passed",
|
|
371
353
|
qualifying: issues.length === 0,
|
|
372
354
|
metrics: {
|
|
@@ -35,7 +35,6 @@ export function main() {
|
|
|
35
35
|
if (mode === "evidence") {
|
|
36
36
|
const result = createWindowsJitEvidence({
|
|
37
37
|
repository: process.env.GITHUB_REPOSITORY,
|
|
38
|
-
campaignId: process.env.AWS_EC2_CAMPAIGN_ID,
|
|
39
38
|
sourceSha:
|
|
40
39
|
process.env.BUILDCHAIN_EXPECTED_SOURCE_SHA || process.env.GITHUB_SHA,
|
|
41
40
|
sourceRef:
|
|
@@ -78,7 +77,6 @@ export function main() {
|
|
|
78
77
|
fs.readFileSync(path.resolve(template), "utf8"),
|
|
79
78
|
{
|
|
80
79
|
region: arg("region", "us-east-1"),
|
|
81
|
-
campaignId: arg("campaign-id"),
|
|
82
80
|
jitParameterName: arg("jit-parameter"),
|
|
83
81
|
evidenceBucket: arg("evidence-bucket"),
|
|
84
82
|
runnerLabel: arg("runner-label"),
|
|
@@ -352,11 +352,7 @@ export function buildStandaloneBinary({
|
|
|
352
352
|
name,
|
|
353
353
|
version,
|
|
354
354
|
platform: triple,
|
|
355
|
-
platformId: process.platform === "linux" && process.arch === "x64" ? "linux-x64" : triple,
|
|
356
355
|
binary: relativePath(cwd, binaryPath),
|
|
357
|
-
sha256: crypto.createHash("sha256").update(fs.readFileSync(binaryPath)).digest("hex"),
|
|
358
|
-
sourceSha: sourceSha(cwd),
|
|
359
|
-
runtimeDependencies: [],
|
|
360
356
|
archive: relativePath(cwd, archivePath),
|
|
361
357
|
node: process.version,
|
|
362
358
|
observability: {
|
|
@@ -208,7 +208,7 @@ export const BUILDCHAIN_USAGE = `Usage:
|
|
|
208
208
|
[--execute] [--json]
|
|
209
209
|
buildchain paper status [--cwd <dir>] [--json]
|
|
210
210
|
buildchain paper resume [--cwd <dir>] [--buildchain-ref <ref>] [--execute] [--json]
|
|
211
|
-
buildchain release-propagation <plan|write-lock
|
|
211
|
+
buildchain release-propagation <plan|write-lock> ...
|
|
212
212
|
buildchain badges readme [--cwd <dir>] [--readme <path>] [--check] [--write] [--json]
|
|
213
213
|
buildchain badges bundle [--cwd <dir>] [--readme <path>] [--claims <csv>] [--check] [--write] [--json]
|
|
214
214
|
buildchain homebrew update-formula --package <name> --release-passport <file-or-url> [--write] [--json]
|
|
@@ -246,7 +246,6 @@ Examples:
|
|
|
246
246
|
buildchain paper preflight --json
|
|
247
247
|
buildchain paper status --json
|
|
248
248
|
buildchain release-propagation plan --graph graph.json --upstream-release release.json --json
|
|
249
|
-
buildchain release-propagation pickup plan --config manual-upstreams.json --source-id buildchain --channel release --current-version 3.0.3 --json
|
|
250
249
|
buildchain kfd status --json
|
|
251
250
|
buildchain kfd schema list --json
|
|
252
251
|
buildchain kfd 1 witness --json
|
|
@@ -49,30 +49,7 @@ function assertSourcePath(value) {
|
|
|
49
49
|
return sourcePath;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
53
|
-
try {
|
|
54
|
-
execFileSync("git", ["cat-file", "-e", `${sourceSha}^{commit}`], {
|
|
55
|
-
cwd,
|
|
56
|
-
stdio: "ignore",
|
|
57
|
-
});
|
|
58
|
-
return true;
|
|
59
|
-
} catch {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function readConfigAtSource(sourceSha, configPath, cwd) {
|
|
65
|
-
if (!hasCommit(sourceSha, cwd)) {
|
|
66
|
-
try {
|
|
67
|
-
execFileSync("git", ["fetch", "--no-tags", "--depth=1", "origin", sourceSha], {
|
|
68
|
-
cwd,
|
|
69
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
70
|
-
});
|
|
71
|
-
} catch (error) {
|
|
72
|
-
const detail = String(error.stderr || error.message || "unknown git fetch failure").trim();
|
|
73
|
-
throw new Error(`exact release source ${sourceSha} is unavailable from origin: ${detail}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
52
|
+
function readConfigAtSource(sourceSha, configPath, cwd) {
|
|
76
53
|
const bytes = execFileSync("git", ["show", `${sourceSha}:${configPath}`], {
|
|
77
54
|
cwd,
|
|
78
55
|
encoding: "utf8",
|
|
@@ -73,7 +73,6 @@ const requiredPaths = [
|
|
|
73
73
|
"docs/github-artifact-attestation.md",
|
|
74
74
|
"docs/shifu-gate-profiles.md",
|
|
75
75
|
"docs/auditable-demo.md",
|
|
76
|
-
"contracts/auditable-demo-scenario-v1.schema.json",
|
|
77
76
|
"contracts/auditable-demo-media-profiles-v1.json",
|
|
78
77
|
"contracts/evidence/auditable-demo-web-delivery-v1.json",
|
|
79
78
|
"contracts/evidence/auditable-demo-responsive-web-delivery-v1.json",
|
|
@@ -104,8 +103,6 @@ const requiredPaths = [
|
|
|
104
103
|
"scripts/seal-macos-credential-input.mjs",
|
|
105
104
|
"scripts/shifu-gate-profile.mjs",
|
|
106
105
|
"scripts/auditable-demo.mjs",
|
|
107
|
-
"scripts/auditable-demo-platform.mjs",
|
|
108
|
-
"scripts/auditable-demo-capture.py",
|
|
109
106
|
"scripts/resolve-artifact-coordinates.mjs",
|
|
110
107
|
"scripts/artifact-relay-s3.mjs",
|
|
111
108
|
"scripts/anchored-version-material.mjs",
|
|
@@ -157,8 +154,6 @@ const requiredPaths = [
|
|
|
157
154
|
".github/workflows/.build.yml",
|
|
158
155
|
".github/workflows/.gate-profile.yml",
|
|
159
156
|
".github/workflows/.auditable-demo.yml",
|
|
160
|
-
".github/workflows/.declarative-auditable-demo.yml",
|
|
161
|
-
".github/workflows/auditable-demo.yml",
|
|
162
157
|
".github/workflows/build.yml",
|
|
163
158
|
".github/workflows/build-surface-fixture.yml",
|
|
164
159
|
".github/workflows/candidate-lab.yml",
|