@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.
Files changed (62) hide show
  1. package/README.md +0 -31
  2. package/actions/macos-credential-island/README.md +0 -8
  3. package/bin/buildchain.mjs +1 -1
  4. package/contracts/auditable-demo-media-profiles-v1.json +0 -61
  5. package/contracts/evidence/auditable-demo-responsive-web-delivery-v1.json +3 -3
  6. package/contracts/evidence/auditable-demo-web-delivery-v1.json +3 -3
  7. package/dist/site/buildchain-contract.json +25 -86
  8. package/dist/site/buildchain-site.json +38 -64
  9. package/dist/site/capability-registry.json +1 -1
  10. package/dist/site/cli-registry.json +2 -6
  11. package/dist/site/controller-registry.json +3 -11
  12. package/dist/site/kfd-claims.json +11 -53
  13. package/dist/site/kfd-upstream-aggregate.json +1 -1
  14. package/dist/site/manual-registry.json +7 -7
  15. package/dist/site/node-api-registry.json +31 -213
  16. package/dist/site/page-registry.json +20 -50
  17. package/dist/site/public-surface-audit.json +8 -98
  18. package/dist/site/publication-authority-registry.json +1 -42
  19. package/dist/site/publication-registry.json +4 -4
  20. package/dist/site/site-manifest.json +11 -11
  21. package/dist/site/workflow-registry.json +2 -67
  22. package/docs/auditable-demo.md +7 -74
  23. package/docs/aws-us-elastic-runner-burst-plane.md +16 -151
  24. package/docs/cli-reference.md +2 -24
  25. package/docs/node-api-reference.md +72 -90
  26. package/docs/publish-transaction.md +5 -7
  27. package/docs/release-flow.md +0 -4
  28. package/docs/release-governance.md +0 -39
  29. package/docs/reusable-build-surface.md +0 -9
  30. package/package.json +1 -1
  31. package/packages/core/buildchain-contract.js +1 -36
  32. package/packages/core/buildchain-publication-authority.js +0 -2
  33. package/packages/core/public-surface-audit.js +35 -4
  34. package/packages/core/release-propagation-release.js +18 -61
  35. package/packages/core/release-propagation-work.js +3 -7
  36. package/packages/core/release-propagation.js +2 -12
  37. package/scripts/auditable-demo-renditions.mjs +2 -7
  38. package/scripts/auditable-demo.mjs +21 -27
  39. package/scripts/aws-windows-jit-controller-core.mjs +2 -20
  40. package/scripts/aws-windows-jit-controller.mjs +109 -184
  41. package/scripts/aws-windows-jit-core.mjs +3 -21
  42. package/scripts/aws-windows-jit.mjs +0 -2
  43. package/scripts/build-standalone-binary.mjs +0 -4
  44. package/scripts/buildchain-cli-help.mjs +1 -2
  45. package/scripts/capture-package-release-propagation.mjs +1 -24
  46. package/scripts/check-inventory.mjs +0 -5
  47. package/scripts/finalize-native-artifact-signing-result.mjs +15 -37
  48. package/scripts/generate-site-bundle.mjs +0 -2
  49. package/scripts/locked-source-checkout.mjs +3 -17
  50. package/scripts/release-propagation.mjs +2 -77
  51. package/contracts/auditable-demo-scenario-v1.schema.json +0 -153
  52. package/packages/core/release-propagation-pickup.js +0 -386
  53. package/packages/core/workflow-call-contract.js +0 -308
  54. package/packages/core/workflow-yaml-contract.js +0 -272
  55. package/scripts/auditable-demo-platform.mjs +0 -506
  56. package/scripts/aws-macos-jit-controller-core.mjs +0 -389
  57. package/scripts/aws-macos-jit-controller-runtime.mjs +0 -82
  58. package/scripts/aws-macos-jit-controller.mjs +0 -558
  59. package/scripts/aws-macos-jit-job-controller.mjs +0 -401
  60. package/scripts/aws-windows-jit-campaign-core.mjs +0 -296
  61. package/scripts/aws-windows-jit-campaign.mjs +0 -202
  62. package/scripts/workflow-call-contract.mjs +0 -133
@@ -1,202 +0,0 @@
1
- #!/usr/bin/env node
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- import { spawnSync } from "node:child_process";
5
- import { pathToFileURL } from "node:url";
6
- import {
7
- createWindowsJitCampaignArmPlan,
8
- windowsCampaignArmItems,
9
- windowsCampaignKillArgs,
10
- } from "./aws-windows-jit-campaign-core.mjs";
11
-
12
- function arg(name, fallback = "") {
13
- const index = process.argv.indexOf(`--${name}`);
14
- return index === -1 ? fallback : process.argv[index + 1] || "";
15
- }
16
-
17
- function aws(plan, serviceArgs) {
18
- const profile = arg("aws-profile");
19
- const result = spawnSync(
20
- "aws",
21
- [
22
- ...(profile ? ["--profile", profile] : []),
23
- "--region",
24
- plan.aws.region,
25
- ...serviceArgs,
26
- ],
27
- { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 },
28
- );
29
- if (result.status !== 0) {
30
- const detail = String(result.stderr || result.stdout || "")
31
- .trim()
32
- .slice(0, 2000);
33
- throw new Error(
34
- `AWS campaign mutation failed${detail ? `: ${detail}` : ""}`,
35
- );
36
- }
37
- return result.stdout ? JSON.parse(result.stdout) : {};
38
- }
39
-
40
- function armPlan() {
41
- return createWindowsJitCampaignArmPlan({
42
- campaignId: arg("campaign-id"),
43
- sourceSha: arg("source-sha"),
44
- stateTable: arg("state-table"),
45
- region: arg("region", "us-east-1"),
46
- armedAt: arg("armed-at", new Date().toISOString()),
47
- expiresAt: arg("expires-at"),
48
- phaseSpendBaselineUsd: arg("phase-spend-baseline-usd"),
49
- maxAcceptedInstances: arg("max-accepted-instances"),
50
- });
51
- }
52
-
53
- function confirm(
54
- plan,
55
- { phaseSpendBaseline = true, maxAcceptedInstances = true } = {},
56
- ) {
57
- if (arg("confirm-campaign-id") !== plan.campaign.id) {
58
- throw new Error("--confirm-campaign-id must equal the campaign id");
59
- }
60
- if (arg("confirm-source-sha") !== plan.source.sha) {
61
- throw new Error("--confirm-source-sha must equal the exact source SHA");
62
- }
63
- if (arg("confirm-state-table") !== plan.aws.stateTable) {
64
- throw new Error(
65
- "--confirm-state-table must equal the campaign state table",
66
- );
67
- }
68
- if (
69
- phaseSpendBaseline &&
70
- (!arg("confirm-phase-spend-baseline-usd").trim() ||
71
- Number(arg("confirm-phase-spend-baseline-usd")) !==
72
- plan.limits.phaseSpendBaselineUsd)
73
- ) {
74
- throw new Error(
75
- "--confirm-phase-spend-baseline-usd must equal the phase spend baseline",
76
- );
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
- }
88
- }
89
-
90
- function killSwitchTopic() {
91
- const topic = arg("kill-switch-topic");
92
- if (
93
- !/^arn:aws:sns:us-east-1:\d{12}:kungfu-buildchain-windows-jit-[A-Za-z0-9_-]+$/.test(
94
- topic,
95
- )
96
- ) {
97
- throw new Error(
98
- "--kill-switch-topic must be the dedicated Windows JIT SNS ARN",
99
- );
100
- }
101
- if (arg("confirm-kill-switch-topic") !== topic) {
102
- throw new Error(
103
- "--confirm-kill-switch-topic must equal the dedicated kill-switch topic",
104
- );
105
- }
106
- return topic;
107
- }
108
-
109
- export function main() {
110
- const mode = process.argv[2] || "plan-arm";
111
- if (["plan-arm", "arm-campaign"].includes(mode)) {
112
- const plan = armPlan();
113
- if (mode === "plan-arm") {
114
- process.stdout.write(`${JSON.stringify(plan, null, 2)}\n`);
115
- return plan;
116
- }
117
- confirm(plan);
118
- aws(plan, [
119
- "dynamodb",
120
- "transact-write-items",
121
- "--transact-items",
122
- JSON.stringify(windowsCampaignArmItems(plan)),
123
- "--output",
124
- "json",
125
- ]);
126
- const result = {
127
- contract: plan.contract,
128
- kind: "campaign-arm-result",
129
- status: "armed",
130
- campaign: plan.campaign,
131
- source: plan.source,
132
- aws: plan.aws,
133
- limits: plan.limits,
134
- };
135
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
136
- return result;
137
- }
138
- if (mode === "kill-campaign") {
139
- const now = new Date();
140
- const plan = createWindowsJitCampaignArmPlan({
141
- campaignId: arg("campaign-id"),
142
- sourceSha: arg("source-sha"),
143
- stateTable: arg("state-table"),
144
- region: arg("region", "us-east-1"),
145
- armedAt: now.toISOString(),
146
- expiresAt: new Date(now.getTime() + 1000).toISOString(),
147
- phaseSpendBaselineUsd: 0,
148
- });
149
- confirm(plan, {
150
- phaseSpendBaseline: false,
151
- maxAcceptedInstances: false,
152
- });
153
- const topic = killSwitchTopic();
154
- aws(
155
- plan,
156
- windowsCampaignKillArgs(
157
- plan.aws.stateTable,
158
- arg("reason", "operator-kill"),
159
- new Date().toISOString(),
160
- ),
161
- );
162
- const notification = aws(plan, [
163
- "sns",
164
- "publish",
165
- "--topic-arn",
166
- topic,
167
- "--message",
168
- JSON.stringify({
169
- contract: plan.contract,
170
- action: "kill-campaign",
171
- campaignId: plan.campaign.id,
172
- sourceSha: plan.source.sha,
173
- }),
174
- "--output",
175
- "json",
176
- ]);
177
- const result = {
178
- contract: plan.contract,
179
- kind: "campaign-kill-result",
180
- status: "killed",
181
- campaign: plan.campaign,
182
- source: plan.source,
183
- killSwitchTopic: topic,
184
- notificationMessageId: notification.MessageId || "",
185
- };
186
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
187
- return result;
188
- }
189
- throw new Error(`unsupported Windows JIT campaign mode: ${mode}`);
190
- }
191
-
192
- if (
193
- process.argv[1] &&
194
- import.meta.url === pathToFileURL(process.argv[1]).href
195
- ) {
196
- try {
197
- main();
198
- } catch (error) {
199
- console.error(`::error::${error.message || error}`);
200
- process.exitCode = 1;
201
- }
202
- }
@@ -1,133 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from "node:fs";
3
- import path from "node:path";
4
- import { execFileSync } from "node:child_process";
5
- import { pathToFileURL } from "node:url";
6
- import { evaluateWorkflowCallContract } from "../packages/core/workflow-call-contract.js";
7
-
8
- function usage() {
9
- return `usage: node scripts/workflow-call-contract.mjs check \\
10
- --caller-workflow <path> --job <id> --caller-repository <owner/repo> \\
11
- --callee-root <checkout> --callee-workflow <path> --callee-repository <owner/repo> \\
12
- --trusted-event <event[:type]> [--trusted-event ...] \\
13
- [--expected-contract-root sha256:...] [--allow-dirty] [--output <path>]`;
14
- }
15
-
16
- function parseArgs(argv) {
17
- const options = { trustedEvents: [] };
18
- for (let index = 0; index < argv.length; index += 1) {
19
- const arg = argv[index];
20
- if (arg === "--allow-dirty") {
21
- options.allowDirty = true;
22
- continue;
23
- }
24
- if (!arg.startsWith("--") || !argv[index + 1])
25
- throw new Error(`invalid argument: ${arg}`);
26
- const value = argv[index + 1];
27
- index += 1;
28
- if (arg === "--trusted-event") options.trustedEvents.push(value);
29
- else
30
- options[
31
- arg.slice(2).replace(/-([a-z])/g, (_, char) => char.toUpperCase())
32
- ] = value;
33
- }
34
- return options;
35
- }
36
-
37
- function git(root, ...args) {
38
- return execFileSync("git", ["-C", root, ...args], {
39
- encoding: "utf8",
40
- }).trim();
41
- }
42
-
43
- function required(options, names) {
44
- const missing = names.filter((name) => !options[name]);
45
- if (missing.length)
46
- throw new Error(`missing required options: ${missing.join(", ")}`);
47
- }
48
-
49
- export function checkWorkflowCall(options) {
50
- const callerRoot = path.resolve(options.callerRoot || process.cwd());
51
- const calleeRoot = path.resolve(options.calleeRoot);
52
- const callerStatus = git(
53
- callerRoot,
54
- "status",
55
- "--porcelain",
56
- "--untracked-files=no",
57
- );
58
- if (callerStatus && !options.allowDirty) {
59
- throw new Error(
60
- "caller checkout is dirty; use --allow-dirty only for local diagnostic validation",
61
- );
62
- }
63
- const calleeStatus = git(
64
- calleeRoot,
65
- "status",
66
- "--porcelain",
67
- "--untracked-files=no",
68
- );
69
- if (calleeStatus) {
70
- throw new Error("callee checkout is dirty; exact pinned-ref bytes are required");
71
- }
72
- const callerSha = git(callerRoot, "rev-parse", "HEAD");
73
- const callerTree = git(callerRoot, "rev-parse", "HEAD^{tree}");
74
- const calleeSha = git(calleeRoot, "rev-parse", "HEAD");
75
- const report = evaluateWorkflowCallContract({
76
- callerText: fs.readFileSync(
77
- path.join(callerRoot, options.callerWorkflow),
78
- "utf8",
79
- ),
80
- calleeText: fs.readFileSync(
81
- path.join(calleeRoot, options.calleeWorkflow),
82
- "utf8",
83
- ),
84
- callerRepository: options.callerRepository,
85
- callerWorkflowPath: options.callerWorkflow,
86
- callerSha,
87
- callerTree,
88
- callerSourceState: callerStatus ? "diagnostic-dirty" : "clean",
89
- calleeRepository: options.calleeRepository,
90
- calleeWorkflowPath: options.calleeWorkflow,
91
- calleeSha,
92
- jobId: options.job,
93
- trustedEventClasses: options.trustedEvents,
94
- expectedContractRoot: options.expectedContractRoot || "",
95
- });
96
- if (options.output) {
97
- const output = path.resolve(callerRoot, options.output);
98
- fs.mkdirSync(path.dirname(output), { recursive: true });
99
- fs.writeFileSync(output, `${JSON.stringify(report, null, 2)}\n`);
100
- }
101
- return report;
102
- }
103
-
104
- function main(argv = process.argv.slice(2)) {
105
- const command = argv.shift();
106
- if (command !== "check") throw new Error(usage());
107
- const options = parseArgs(argv);
108
- required(options, [
109
- "callerWorkflow",
110
- "job",
111
- "callerRepository",
112
- "calleeRoot",
113
- "calleeWorkflow",
114
- "calleeRepository",
115
- ]);
116
- if (!options.trustedEvents.length)
117
- throw new Error("at least one --trusted-event is required");
118
- const report = checkWorkflowCall(options);
119
- process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
120
- if (!report.ok) process.exitCode = 1;
121
- }
122
-
123
- if (
124
- process.argv[1] &&
125
- import.meta.url === pathToFileURL(process.argv[1]).href
126
- ) {
127
- try {
128
- main();
129
- } catch (error) {
130
- console.error(`workflow call contract: ${error.message}`);
131
- process.exitCode = 1;
132
- }
133
- }