@kungfu-tech/buildchain 3.0.5-alpha.5 → 3.0.5-alpha.7
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 +31 -0
- package/actions/macos-credential-island/README.md +8 -0
- package/bin/buildchain.mjs +1 -1
- package/contracts/auditable-demo-media-profiles-v1.json +61 -0
- package/contracts/auditable-demo-scenario-v1.schema.json +153 -0
- 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 +57 -6
- package/dist/site/buildchain-site.json +42 -26
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/cli-registry.json +6 -2
- package/dist/site/kfd-claims.json +49 -9
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +3 -3
- package/dist/site/node-api-registry.json +205 -23
- package/dist/site/page-registry.json +32 -12
- package/dist/site/public-surface-audit.json +94 -6
- package/dist/site/publication-authority-registry.json +42 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +7 -7
- package/dist/site/workflow-registry.json +63 -0
- package/docs/auditable-demo.md +74 -7
- package/docs/aws-us-elastic-runner-burst-plane.md +16 -6
- package/docs/cli-reference.md +24 -2
- package/docs/node-api-reference.md +69 -51
- package/package.json +1 -1
- package/packages/core/buildchain-contract.js +36 -1
- package/packages/core/buildchain-publication-authority.js +2 -0
- package/packages/core/release-propagation-pickup.js +386 -0
- package/packages/core/release-propagation-release.js +61 -18
- package/packages/core/release-propagation-work.js +7 -3
- package/packages/core/release-propagation.js +12 -2
- package/scripts/auditable-demo-platform.mjs +506 -0
- package/scripts/auditable-demo-renditions.mjs +6 -1
- package/scripts/auditable-demo.mjs +14 -4
- package/scripts/aws-windows-jit-campaign-core.mjs +19 -3
- package/scripts/aws-windows-jit-campaign.mjs +19 -2
- package/scripts/build-standalone-binary.mjs +4 -0
- package/scripts/buildchain-cli-help.mjs +2 -1
- package/scripts/check-inventory.mjs +5 -0
- package/scripts/finalize-native-artifact-signing-result.mjs +37 -15
- package/scripts/generate-site-bundle.mjs +2 -0
- package/scripts/release-propagation.mjs +77 -2
|
@@ -46,10 +46,14 @@ function armPlan() {
|
|
|
46
46
|
armedAt: arg("armed-at", new Date().toISOString()),
|
|
47
47
|
expiresAt: arg("expires-at"),
|
|
48
48
|
phaseSpendBaselineUsd: arg("phase-spend-baseline-usd"),
|
|
49
|
+
maxAcceptedInstances: arg("max-accepted-instances"),
|
|
49
50
|
});
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
function confirm(
|
|
53
|
+
function confirm(
|
|
54
|
+
plan,
|
|
55
|
+
{ phaseSpendBaseline = true, maxAcceptedInstances = true } = {},
|
|
56
|
+
) {
|
|
53
57
|
if (arg("confirm-campaign-id") !== plan.campaign.id) {
|
|
54
58
|
throw new Error("--confirm-campaign-id must equal the campaign id");
|
|
55
59
|
}
|
|
@@ -71,6 +75,16 @@ function confirm(plan, { phaseSpendBaseline = true } = {}) {
|
|
|
71
75
|
"--confirm-phase-spend-baseline-usd must equal the phase spend baseline",
|
|
72
76
|
);
|
|
73
77
|
}
|
|
78
|
+
if (
|
|
79
|
+
maxAcceptedInstances &&
|
|
80
|
+
(!arg("confirm-max-accepted-instances").trim() ||
|
|
81
|
+
Number(arg("confirm-max-accepted-instances")) !==
|
|
82
|
+
plan.limits.maxAcceptedInstances)
|
|
83
|
+
) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
"--confirm-max-accepted-instances must equal the campaign slot ceiling",
|
|
86
|
+
);
|
|
87
|
+
}
|
|
74
88
|
}
|
|
75
89
|
|
|
76
90
|
function killSwitchTopic() {
|
|
@@ -132,7 +146,10 @@ export function main() {
|
|
|
132
146
|
expiresAt: new Date(now.getTime() + 1000).toISOString(),
|
|
133
147
|
phaseSpendBaselineUsd: 0,
|
|
134
148
|
});
|
|
135
|
-
confirm(plan, {
|
|
149
|
+
confirm(plan, {
|
|
150
|
+
phaseSpendBaseline: false,
|
|
151
|
+
maxAcceptedInstances: false,
|
|
152
|
+
});
|
|
136
153
|
const topic = killSwitchTopic();
|
|
137
154
|
aws(
|
|
138
155
|
plan,
|
|
@@ -352,7 +352,11 @@ export function buildStandaloneBinary({
|
|
|
352
352
|
name,
|
|
353
353
|
version,
|
|
354
354
|
platform: triple,
|
|
355
|
+
platformId: process.platform === "linux" && process.arch === "x64" ? "linux-x64" : triple,
|
|
355
356
|
binary: relativePath(cwd, binaryPath),
|
|
357
|
+
sha256: crypto.createHash("sha256").update(fs.readFileSync(binaryPath)).digest("hex"),
|
|
358
|
+
sourceSha: sourceSha(cwd),
|
|
359
|
+
runtimeDependencies: [],
|
|
356
360
|
archive: relativePath(cwd, archivePath),
|
|
357
361
|
node: process.version,
|
|
358
362
|
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|work|pickup> ...
|
|
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,6 +246,7 @@ 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
|
|
249
250
|
buildchain kfd status --json
|
|
250
251
|
buildchain kfd schema list --json
|
|
251
252
|
buildchain kfd 1 witness --json
|
|
@@ -73,6 +73,7 @@ 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",
|
|
76
77
|
"contracts/auditable-demo-media-profiles-v1.json",
|
|
77
78
|
"contracts/evidence/auditable-demo-web-delivery-v1.json",
|
|
78
79
|
"contracts/evidence/auditable-demo-responsive-web-delivery-v1.json",
|
|
@@ -103,6 +104,8 @@ const requiredPaths = [
|
|
|
103
104
|
"scripts/seal-macos-credential-input.mjs",
|
|
104
105
|
"scripts/shifu-gate-profile.mjs",
|
|
105
106
|
"scripts/auditable-demo.mjs",
|
|
107
|
+
"scripts/auditable-demo-platform.mjs",
|
|
108
|
+
"scripts/auditable-demo-capture.py",
|
|
106
109
|
"scripts/resolve-artifact-coordinates.mjs",
|
|
107
110
|
"scripts/artifact-relay-s3.mjs",
|
|
108
111
|
"scripts/anchored-version-material.mjs",
|
|
@@ -154,6 +157,8 @@ const requiredPaths = [
|
|
|
154
157
|
".github/workflows/.build.yml",
|
|
155
158
|
".github/workflows/.gate-profile.yml",
|
|
156
159
|
".github/workflows/.auditable-demo.yml",
|
|
160
|
+
".github/workflows/.declarative-auditable-demo.yml",
|
|
161
|
+
".github/workflows/auditable-demo.yml",
|
|
157
162
|
".github/workflows/build.yml",
|
|
158
163
|
".github/workflows/build-surface-fixture.yml",
|
|
159
164
|
".github/workflows/candidate-lab.yml",
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
artifactSigningEvidenceDigest,
|
|
13
13
|
createArtifactSigningResult,
|
|
14
14
|
} from "../packages/core/artifact-signing-result.js";
|
|
15
|
+
import { acceptedMacosCredentialEvidence } from "../actions/macos-credential-island/dmg-assembly.js";
|
|
15
16
|
import { writeGitHubOutputs } from "./build-contract-core.mjs";
|
|
16
17
|
|
|
17
18
|
function required(value, label) {
|
|
@@ -32,15 +33,39 @@ function resolveBelow(root, relative, label) {
|
|
|
32
33
|
return target;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
function expectedCredentialExecution(
|
|
37
|
+
appBundleResult,
|
|
38
|
+
expectedRunId,
|
|
39
|
+
expectedRunAttempt,
|
|
40
|
+
) {
|
|
41
|
+
if (!appBundleResult) return null;
|
|
42
|
+
return {
|
|
43
|
+
runId: required(expectedRunId, "credential execution run id"),
|
|
44
|
+
runAttempt: required(
|
|
45
|
+
expectedRunAttempt,
|
|
46
|
+
"credential execution run attempt",
|
|
47
|
+
),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function acceptedProviderEvidence(evidence, request, expectedExecution) {
|
|
52
|
+
return expectedExecution
|
|
53
|
+
? acceptedMacosCredentialEvidence(evidence, request, expectedExecution)
|
|
54
|
+
: evidence.status === "passed" &&
|
|
55
|
+
evidence.provider === request.signature.provider;
|
|
56
|
+
}
|
|
57
|
+
|
|
35
58
|
export function finalizeNativeArtifactSigningResult({
|
|
36
59
|
requestRoot = process.env.BUILDCHAIN_SIGNING_REQUEST_ROOT,
|
|
37
60
|
requestPath = process.env.BUILDCHAIN_SIGNING_REQUEST_PATH,
|
|
38
61
|
signedPayload = process.env.BUILDCHAIN_SIGNED_PAYLOAD,
|
|
39
62
|
evidencePath = process.env.BUILDCHAIN_SIGNING_EVIDENCE,
|
|
40
|
-
credentialArtifactRoot =
|
|
41
|
-
|
|
63
|
+
credentialArtifactRoot = process.env
|
|
64
|
+
.BUILDCHAIN_SIGNING_CREDENTIAL_ARTIFACT_ROOT,
|
|
42
65
|
outputRoot = process.env.BUILDCHAIN_SIGNING_RESULT_ROOT,
|
|
43
66
|
checks = process.env.BUILDCHAIN_SIGNING_VERIFICATION_CHECKS,
|
|
67
|
+
expectedRunId = process.env.GITHUB_RUN_ID,
|
|
68
|
+
expectedRunAttempt = process.env.GITHUB_RUN_ATTEMPT,
|
|
44
69
|
} = {}) {
|
|
45
70
|
const requests = path.resolve(required(requestRoot, "signing request root"));
|
|
46
71
|
const request = JSON.parse(
|
|
@@ -77,19 +102,16 @@ export function finalizeNativeArtifactSigningResult({
|
|
|
77
102
|
fs.copyFileSync(evidenceSource, evidenceOutput, fs.constants.COPYFILE_EXCL);
|
|
78
103
|
const evidenceDocument = JSON.parse(fs.readFileSync(evidenceOutput, "utf8"));
|
|
79
104
|
const appBundleResult = request.artifact.kind === "app-bundle";
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
evidenceDocument.notarization?.diskImage?.status === "Accepted"
|
|
91
|
-
: evidenceDocument.status === "passed" &&
|
|
92
|
-
evidenceDocument.provider === request.signature.provider;
|
|
105
|
+
const expectedExecution = expectedCredentialExecution(
|
|
106
|
+
appBundleResult,
|
|
107
|
+
expectedRunId,
|
|
108
|
+
expectedRunAttempt,
|
|
109
|
+
);
|
|
110
|
+
const providerEvidencePassed = acceptedProviderEvidence(
|
|
111
|
+
evidenceDocument,
|
|
112
|
+
request,
|
|
113
|
+
expectedExecution,
|
|
114
|
+
);
|
|
93
115
|
if (!providerEvidencePassed) {
|
|
94
116
|
throw new Error(
|
|
95
117
|
"provider evidence does not prove the requested native signature",
|
|
@@ -767,6 +767,7 @@ function buildSiteBundle() {
|
|
|
767
767
|
["build", "channel-build-router"],
|
|
768
768
|
[".build", "reusable-build"],
|
|
769
769
|
[".auditable-demo", "auditable-demo"],
|
|
770
|
+
[".declarative-auditable-demo", "declarative-auditable-demo"],
|
|
770
771
|
["web-surface", "site-app-deployment"],
|
|
771
772
|
["buildchain-ref-promotion", "release-governance"],
|
|
772
773
|
["release-line-bootstrap", "release-governance"],
|
|
@@ -793,6 +794,7 @@ function buildSiteBundle() {
|
|
|
793
794
|
]);
|
|
794
795
|
const statusById = new Map([
|
|
795
796
|
[".auditable-demo", "preview"],
|
|
797
|
+
[".declarative-auditable-demo", "preview"],
|
|
796
798
|
["release-propagation", "preview"],
|
|
797
799
|
["candidate-lab", "repository-internal"],
|
|
798
800
|
["build-surface-fixture", "repository-internal"],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
4
5
|
import { pathToFileURL } from "node:url";
|
|
5
6
|
import {
|
|
6
7
|
claimReleasePropagationWork,
|
|
@@ -15,6 +16,10 @@ import {
|
|
|
15
16
|
resumeReleasePropagationWork,
|
|
16
17
|
verifyReleasePropagationWork,
|
|
17
18
|
writeReleasePropagationLock,
|
|
19
|
+
createManualUpstreamPickupCapture,
|
|
20
|
+
createManualUpstreamPickupPlan,
|
|
21
|
+
normalizeManualUpstreamPickupConfig,
|
|
22
|
+
resolveNpmRegistryRelease,
|
|
18
23
|
} from "../packages/core/release-propagation.js";
|
|
19
24
|
|
|
20
25
|
function usage() {
|
|
@@ -61,6 +66,15 @@ function usage() {
|
|
|
61
66
|
--completion-decision <json-or-path>
|
|
62
67
|
--expected-work-root <sha256:...>
|
|
63
68
|
[--output <file>] [--json]
|
|
69
|
+
buildchain release-propagation pickup plan --config <json-or-path>
|
|
70
|
+
--source-id <id> --channel <alpha|release>
|
|
71
|
+
--current-version <version>
|
|
72
|
+
[--output <file>] [--json]
|
|
73
|
+
buildchain release-propagation pickup create --config <json-or-path>
|
|
74
|
+
--source-id <id> --channel <alpha|release>
|
|
75
|
+
--current-version <version>
|
|
76
|
+
--expected-downstream-base-sha <git-sha>
|
|
77
|
+
[--output <file>] [--json]
|
|
64
78
|
`;
|
|
65
79
|
}
|
|
66
80
|
|
|
@@ -171,7 +185,61 @@ function runWorkCli(args) {
|
|
|
171
185
|
throw new Error(`unsupported release-propagation work command: ${mode}`);
|
|
172
186
|
}
|
|
173
187
|
|
|
174
|
-
|
|
188
|
+
async function resolvePickupPlan(args) {
|
|
189
|
+
const config = normalizeManualUpstreamPickupConfig(readJsonFlag(args, "config"));
|
|
190
|
+
const sourceId = readFlag(args, "source-id");
|
|
191
|
+
const channel = readFlag(args, "channel");
|
|
192
|
+
const source = config.sources.find((entry) => entry.id === sourceId);
|
|
193
|
+
if (!source) throw new Error(`manual pickup source is not configured: ${sourceId}`);
|
|
194
|
+
const distTag = source.distTags[channel];
|
|
195
|
+
if (!distTag) throw new Error("manual pickup channel must be alpha or release");
|
|
196
|
+
const packageMetadata = args.includes("--package-metadata")
|
|
197
|
+
? readJsonFlag(args, "package-metadata")
|
|
198
|
+
: JSON.parse(execFileSync("npm", ["view", `${source.package}@${distTag}`, "--json", "--registry=https://registry.npmjs.org/"], {
|
|
199
|
+
encoding: "utf8",
|
|
200
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
201
|
+
}));
|
|
202
|
+
const attestationUrl = packageMetadata.dist?.attestations?.url;
|
|
203
|
+
if (!attestationUrl) throw new Error("published npm package does not expose an attestation URL");
|
|
204
|
+
let attestations;
|
|
205
|
+
if (args.includes("--attestations")) {
|
|
206
|
+
attestations = readJsonFlag(args, "attestations");
|
|
207
|
+
} else {
|
|
208
|
+
const response = await fetch(attestationUrl, { headers: { accept: "application/json" } });
|
|
209
|
+
if (!response.ok) throw new Error(`npm attestation lookup failed: HTTP ${response.status}`);
|
|
210
|
+
attestations = await response.json();
|
|
211
|
+
}
|
|
212
|
+
const upstreamRelease = resolveNpmRegistryRelease({ source, channel, packageMetadata, attestations });
|
|
213
|
+
return createManualUpstreamPickupPlan({
|
|
214
|
+
config,
|
|
215
|
+
sourceId,
|
|
216
|
+
channel,
|
|
217
|
+
currentVersion: readFlag(args, "current-version"),
|
|
218
|
+
upstreamRelease,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function runPickupCli(args) {
|
|
223
|
+
const [mode = "", ...pickupArgs] = args;
|
|
224
|
+
if (!mode || mode === "--help" || mode === "-h") {
|
|
225
|
+
process.stdout.write(usage());
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (mode !== "plan" && mode !== "create") throw new Error(`unsupported release-propagation pickup command: ${mode}`);
|
|
229
|
+
const plan = await resolvePickupPlan(pickupArgs);
|
|
230
|
+
const result = mode === "create"
|
|
231
|
+
? createManualUpstreamPickupCapture({
|
|
232
|
+
plan,
|
|
233
|
+
expectedDownstreamBaseSha: readFlag(pickupArgs, "expected-downstream-base-sha"),
|
|
234
|
+
})
|
|
235
|
+
: plan;
|
|
236
|
+
writeOutput(readFlag(pickupArgs, "output", ""), result);
|
|
237
|
+
if (hasFlag(pickupArgs, "json")) printJson(result);
|
|
238
|
+
else if (mode === "plan") process.stdout.write(`manual upstream pickup: ${plan.source.id} ${plan.currentVersion} -> ${plan.resolvedVersion} (${plan.status})\n`);
|
|
239
|
+
else process.stdout.write(`manual upstream pickup next action: ${result.nextAction}\n`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function runReleasePropagationCli(argv = process.argv.slice(2)) {
|
|
175
243
|
const [mode = "", ...args] = argv;
|
|
176
244
|
if (!mode || mode === "--help" || mode === "-h") {
|
|
177
245
|
process.stdout.write(usage());
|
|
@@ -206,6 +274,10 @@ export function runReleasePropagationCli(argv = process.argv.slice(2)) {
|
|
|
206
274
|
runWorkCli(args);
|
|
207
275
|
return;
|
|
208
276
|
}
|
|
277
|
+
if (mode === "pickup") {
|
|
278
|
+
await runPickupCli(args);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
209
281
|
if (mode === "write-lock") {
|
|
210
282
|
const plan = readReleasePropagationJson(readFlag(args, "plan"), {
|
|
211
283
|
label: "--plan",
|
|
@@ -259,5 +331,8 @@ export function runReleasePropagationCli(argv = process.argv.slice(2)) {
|
|
|
259
331
|
}
|
|
260
332
|
|
|
261
333
|
if (!process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
262
|
-
runReleasePropagationCli()
|
|
334
|
+
runReleasePropagationCli().catch((error) => {
|
|
335
|
+
console.error(`buildchain release-propagation: ${error.message}`);
|
|
336
|
+
process.exitCode = 1;
|
|
337
|
+
});
|
|
263
338
|
}
|