@kungfu-tech/buildchain 3.0.4-alpha.2 → 3.0.4-alpha.3

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 (49) hide show
  1. package/bin/buildchain.mjs +126 -72
  2. package/bin/internal/trust-release-cli.mjs +15 -537
  3. package/bin/internal/trust-release-command-handlers.mjs +14 -0
  4. package/bin/internal/trust-release-inspection-handlers.mjs +175 -0
  5. package/bin/internal/trust-release-release-handlers.mjs +317 -0
  6. package/bin/internal/trust-release-verification-handlers.mjs +306 -0
  7. package/dist/site/buildchain-contract.json +35 -24
  8. package/dist/site/buildchain-site.json +22 -10
  9. package/dist/site/controller-registry.json +16 -3
  10. package/dist/site/kfd-claims.json +9 -7
  11. package/dist/site/kfd-upstream-aggregate.json +1 -1
  12. package/dist/site/manual-registry.json +2 -2
  13. package/dist/site/node-api-registry.json +7 -7
  14. package/dist/site/page-registry.json +9 -4
  15. package/dist/site/public-surface-audit.json +56 -8
  16. package/dist/site/publication-registry.json +4 -4
  17. package/dist/site/release-model.json +7 -0
  18. package/dist/site/site-manifest.json +6 -6
  19. package/dist/site/workflow-registry.json +13 -5
  20. package/docs/MAP.md +1 -1
  21. package/docs/release-propagation.md +166 -8
  22. package/package.json +1 -1
  23. package/packages/core/buildchain-kfd-claims.js +1 -1
  24. package/packages/core/controller-evidence.js +8 -1
  25. package/packages/core/index.js +1 -13
  26. package/packages/core/paper-npm-bootstrap.js +492 -0
  27. package/packages/core/paper.js +271 -669
  28. package/packages/core/public-surface-cli.js +12 -1
  29. package/packages/core/release-passport.js +67 -71
  30. package/packages/core/release-propagation-common.js +64 -0
  31. package/packages/core/release-propagation-execution-profile.js +59 -0
  32. package/packages/core/release-propagation-release.js +196 -0
  33. package/packages/core/release-propagation-stage-evidence.js +364 -0
  34. package/packages/core/release-propagation-work-capture.js +64 -0
  35. package/packages/core/release-propagation-work-constants.js +34 -0
  36. package/packages/core/release-propagation-work-control.js +203 -0
  37. package/packages/core/release-propagation-work-transitions.js +145 -0
  38. package/packages/core/release-propagation-work.js +517 -0
  39. package/packages/core/release-propagation.js +34 -158
  40. package/scripts/aws-windows-jit-controller-core.mjs +269 -0
  41. package/scripts/aws-windows-jit-controller.mjs +502 -0
  42. package/scripts/check-internal-architecture.mjs +178 -52
  43. package/scripts/check-maintainability.mjs +76 -17
  44. package/scripts/generate-site-bundle.mjs +16 -7
  45. package/scripts/maintainability-metrics.mjs +24 -4
  46. package/scripts/release-propagation.mjs +126 -0
  47. package/scripts/resolve-artifact-transfer-mode.mjs +117 -0
  48. package/scripts/web-surface-core.mjs +46 -207
  49. package/scripts/web-surface-routing.mjs +286 -0
@@ -0,0 +1,492 @@
1
+ function executePaperNpmBootstrap(options = {}, runtime) {
2
+ const {
3
+ DEFAULT_BOOTSTRAP_VERSION,
4
+ NPM_REGISTRY,
5
+ PAPER_NPM_BOOTSTRAP_CONTRACT,
6
+ PAPER_PATHS,
7
+ bootstrapPackageShape,
8
+ commandResult,
9
+ expectedPaperTrustedPublisher,
10
+ extractUrls,
11
+ fs,
12
+ jsonText,
13
+ liveNpmAuthObservation,
14
+ liveNpmPackageObservation,
15
+ liveNpmTrustObservation,
16
+ normalizePackageName,
17
+ normalizeRepository,
18
+ os,
19
+ paperConfig,
20
+ path,
21
+ resolvePaperRepository,
22
+ safeParseJson,
23
+ toPosix,
24
+ validatePaperProvisioningAuthority,
25
+ writePaperReceipt,
26
+ } = runtime;
27
+ const {
28
+ cwd = process.cwd(),
29
+ packageName = "",
30
+ bootstrapVersion = DEFAULT_BOOTSTRAP_VERSION,
31
+ registry = NPM_REGISTRY,
32
+ repository = "",
33
+ workflow = "paper-release.yml",
34
+ environment = "",
35
+ execute = false,
36
+ confirmedPackage = "",
37
+ userconfig = "",
38
+ offline = false,
39
+ } = options;
40
+ const resolvedCwd = path.resolve(cwd);
41
+ if (registry !== NPM_REGISTRY) {
42
+ throw new Error(
43
+ `paper npm bootstrap requires the official registry ${NPM_REGISTRY}`,
44
+ );
45
+ }
46
+ if (bootstrapVersion !== DEFAULT_BOOTSTRAP_VERSION) {
47
+ throw new Error(
48
+ `paper npm bootstrap version is fixed at ${DEFAULT_BOOTSTRAP_VERSION}`,
49
+ );
50
+ }
51
+ const configResult = paperConfig(resolvedCwd);
52
+ if (configResult.error) throw new Error(configResult.error);
53
+ const name = normalizePackageName(
54
+ packageName ||
55
+ configResult.loaded.config.publish?.package ||
56
+ configResult.loaded.config.publish?.mainPackage,
57
+ );
58
+ const repo = normalizeRepository(
59
+ repository || resolvePaperRepository(resolvedCwd),
60
+ );
61
+ const provisioning = validatePaperProvisioningAuthority(resolvedCwd);
62
+ if (!provisioning.valid) {
63
+ throw new Error(
64
+ `paper npm bootstrap requires a valid provisioning authority: ${provisioning.errors.join("; ")}`,
65
+ );
66
+ }
67
+ const expectedPublisher = expectedPaperTrustedPublisher(provisioning.value);
68
+ if (
69
+ provisioning.value.package?.name !== name ||
70
+ expectedPublisher.repository !== repo ||
71
+ expectedPublisher.workflow !== toPosix(workflow).replace(/^\/+/, "") ||
72
+ expectedPublisher.environment !== String(environment || "")
73
+ ) {
74
+ throw new Error(
75
+ "paper npm bootstrap coordinates differ from the exact provisioning authority",
76
+ );
77
+ }
78
+ if (execute && confirmedPackage !== name) {
79
+ throw new Error(
80
+ `real npm bootstrap requires --confirm-public-package ${name}`,
81
+ );
82
+ }
83
+ if (execute && offline) {
84
+ throw new Error("real npm bootstrap cannot run with --offline");
85
+ }
86
+ if (execute && (!repo || !workflow)) {
87
+ throw new Error(
88
+ "real npm bootstrap requires GitHub repository and workflow coordinates",
89
+ );
90
+ }
91
+ const packageObservation = offline
92
+ ? {
93
+ status: "unknown",
94
+ exists: null,
95
+ version: "",
96
+ registry,
97
+ errorCode: "offline",
98
+ }
99
+ : liveNpmPackageObservation(name, registry, resolvedCwd);
100
+ const auth = offline
101
+ ? {
102
+ status: "unknown",
103
+ authenticated: null,
104
+ identity: "",
105
+ errorCode: "offline",
106
+ }
107
+ : liveNpmAuthObservation(registry, resolvedCwd);
108
+ const plan = {
109
+ schemaVersion: 1,
110
+ contract: PAPER_NPM_BOOTSTRAP_CONTRACT,
111
+ ok: true,
112
+ dryRun: !execute,
113
+ externalMutation: execute,
114
+ package: {
115
+ name,
116
+ bootstrapVersion,
117
+ registry,
118
+ existsBefore: packageObservation.exists,
119
+ observedVersion: packageObservation.version,
120
+ },
121
+ repository: {
122
+ github: repo,
123
+ workflow,
124
+ environment,
125
+ },
126
+ authority: {
127
+ digest: provisioning.value.authorityDigest,
128
+ policyDigest: provisioning.value.policy.policyDigest,
129
+ },
130
+ auth: {
131
+ authenticated: auth.authenticated,
132
+ identity: auth.identity,
133
+ errorCode: auth.errorCode,
134
+ },
135
+ publish: {
136
+ status: packageObservation.exists === true ? "existing" : "planned",
137
+ distTag: "bootstrap",
138
+ access: "public",
139
+ },
140
+ trust: {
141
+ status: "planned",
142
+ urls: [],
143
+ },
144
+ receipts: [],
145
+ nextActions: execute
146
+ ? []
147
+ : [
148
+ {
149
+ id: "confirm-public-bootstrap",
150
+ command: `buildchain paper bootstrap npm --execute --confirm-public-package ${name} --json`,
151
+ description:
152
+ "After reviewing this dry-run, bootstrap the exact public package and configure GitHub Trusted Publishing.",
153
+ },
154
+ ],
155
+ };
156
+ if (!execute) {
157
+ const dryRunRoot = fs.mkdtempSync(
158
+ path.join(os.tmpdir(), "buildchain-paper-bootstrap-dry-run-"),
159
+ );
160
+ try {
161
+ fs.writeFileSync(
162
+ path.join(dryRunRoot, "package.json"),
163
+ jsonText(
164
+ bootstrapPackageShape({
165
+ packageName: name,
166
+ version: bootstrapVersion,
167
+ }),
168
+ ),
169
+ );
170
+ const configArgs = userconfig ? ["--userconfig", userconfig] : [];
171
+ const pack = commandResult(
172
+ "npm",
173
+ [
174
+ "pack",
175
+ "--dry-run",
176
+ "--json",
177
+ "--ignore-scripts",
178
+ `--registry=${registry}`,
179
+ ...configArgs,
180
+ ],
181
+ { cwd: dryRunRoot },
182
+ );
183
+ const publish = commandResult(
184
+ "npm",
185
+ [
186
+ "publish",
187
+ "--dry-run",
188
+ "--ignore-scripts",
189
+ "--access",
190
+ "public",
191
+ "--tag",
192
+ "bootstrap",
193
+ `--registry=${registry}`,
194
+ ...configArgs,
195
+ ],
196
+ { cwd: dryRunRoot },
197
+ );
198
+ return {
199
+ ...plan,
200
+ ok: pack.ok && publish.ok,
201
+ errorCode: !pack.ok
202
+ ? "npm-pack-dry-run-failed"
203
+ : !publish.ok
204
+ ? "npm-publish-dry-run-failed"
205
+ : "",
206
+ dryRunChecks: {
207
+ minimalPackageOnly: true,
208
+ pack: {
209
+ status: pack.ok ? "pass" : "fail",
210
+ entryCount: (() => {
211
+ const parsed = safeParseJson(pack.stdout);
212
+ const value = Array.isArray(parsed) ? parsed[0] : parsed;
213
+ return Array.isArray(value?.files) ? value.files.length : 0;
214
+ })(),
215
+ },
216
+ publish: {
217
+ status: publish.ok ? "pass" : "fail",
218
+ registry,
219
+ access: "public",
220
+ distTag: "bootstrap",
221
+ },
222
+ },
223
+ };
224
+ } finally {
225
+ fs.rmSync(dryRunRoot, { recursive: true, force: true });
226
+ }
227
+ }
228
+ if (packageObservation.exists === null) {
229
+ return {
230
+ ...plan,
231
+ ok: false,
232
+ errorCode: "npm-package-status-unknown",
233
+ publish: {
234
+ ...plan.publish,
235
+ status: "blocked",
236
+ },
237
+ trust: {
238
+ status: "blocked",
239
+ urls: [],
240
+ },
241
+ nextActions: [
242
+ {
243
+ id: "verify-npm-package",
244
+ command: `npm view ${name} version --json --registry=${registry}`,
245
+ description:
246
+ "Resolve whether the exact public package exists before any publish mutation.",
247
+ },
248
+ ],
249
+ };
250
+ }
251
+ if (auth.authenticated !== true) {
252
+ return {
253
+ ...plan,
254
+ ok: false,
255
+ errorCode: "npm-auth-required",
256
+ publish: {
257
+ ...plan.publish,
258
+ status: "blocked",
259
+ },
260
+ trust: {
261
+ status: "blocked",
262
+ urls: [],
263
+ },
264
+ nextActions: [
265
+ {
266
+ id: "authenticate-npm",
267
+ command: `npm whoami --registry=${registry}`,
268
+ description:
269
+ "Authenticate npm without sharing token contents, then rerun the exact bootstrap command.",
270
+ },
271
+ ],
272
+ };
273
+ }
274
+ const tempRoot = fs.mkdtempSync(
275
+ path.join(os.tmpdir(), "buildchain-paper-bootstrap-"),
276
+ );
277
+ try {
278
+ fs.writeFileSync(
279
+ path.join(tempRoot, "package.json"),
280
+ jsonText(
281
+ bootstrapPackageShape({ packageName: name, version: bootstrapVersion }),
282
+ ),
283
+ );
284
+ const configArgs = userconfig ? ["--userconfig", userconfig] : [];
285
+ const pack = commandResult(
286
+ "npm",
287
+ [
288
+ "pack",
289
+ "--dry-run",
290
+ "--json",
291
+ "--ignore-scripts",
292
+ `--registry=${registry}`,
293
+ ...configArgs,
294
+ ],
295
+ { cwd: tempRoot },
296
+ );
297
+ if (!pack.ok) {
298
+ return {
299
+ ...plan,
300
+ ok: false,
301
+ errorCode: "npm-pack-dry-run-failed",
302
+ publish: { ...plan.publish, status: "blocked" },
303
+ trust: { status: "blocked", urls: [] },
304
+ };
305
+ }
306
+ const publishDryRun = commandResult(
307
+ "npm",
308
+ [
309
+ "publish",
310
+ "--dry-run",
311
+ "--ignore-scripts",
312
+ "--access",
313
+ "public",
314
+ "--tag",
315
+ "bootstrap",
316
+ `--registry=${registry}`,
317
+ ...configArgs,
318
+ ],
319
+ { cwd: tempRoot },
320
+ );
321
+ if (!publishDryRun.ok) {
322
+ return {
323
+ ...plan,
324
+ ok: false,
325
+ errorCode: "npm-publish-dry-run-failed",
326
+ publish: { ...plan.publish, status: "blocked" },
327
+ trust: { status: "blocked", urls: [] },
328
+ };
329
+ }
330
+ let publishStatus =
331
+ packageObservation.exists === true ? "existing" : "published";
332
+ if (packageObservation.exists !== true) {
333
+ const published = commandResult(
334
+ "npm",
335
+ [
336
+ "publish",
337
+ "--ignore-scripts",
338
+ "--access",
339
+ "public",
340
+ "--tag",
341
+ "bootstrap",
342
+ `--registry=${registry}`,
343
+ ...configArgs,
344
+ ],
345
+ { cwd: tempRoot, timeout: 60000 },
346
+ );
347
+ if (!published.ok) {
348
+ const failure = {
349
+ ...plan,
350
+ ok: false,
351
+ errorCode: "npm-publish-failed",
352
+ publish: { ...plan.publish, status: "failed" },
353
+ trust: { status: "blocked", urls: [] },
354
+ };
355
+ failure.receipts = [
356
+ writePaperReceipt(resolvedCwd, PAPER_PATHS.npmBootstrap, failure),
357
+ ];
358
+ return failure;
359
+ }
360
+ }
361
+ const trustArgs = [
362
+ "trust",
363
+ "github",
364
+ name,
365
+ "--repo",
366
+ repo,
367
+ "--file",
368
+ workflow,
369
+ ...(environment ? ["--env", environment] : []),
370
+ "--allow-publish",
371
+ "--yes",
372
+ "--json",
373
+ `--registry=${registry}`,
374
+ ...configArgs,
375
+ ];
376
+ const trustCommand = commandResult("npm", trustArgs, {
377
+ cwd: resolvedCwd,
378
+ timeout: 60000,
379
+ });
380
+ const parsedTrust = safeParseJson(trustCommand.stdout);
381
+ const urls = [
382
+ ...extractUrls(
383
+ parsedTrust || `${trustCommand.stdout}\n${trustCommand.stderr}`,
384
+ ),
385
+ ];
386
+ const trustList =
387
+ trustCommand.ok && urls.length === 0
388
+ ? liveNpmTrustObservation(
389
+ name,
390
+ registry,
391
+ resolvedCwd,
392
+ expectedPublisher,
393
+ )
394
+ : {
395
+ status: "unknown",
396
+ configured: null,
397
+ publishers: [],
398
+ errorCode:
399
+ urls.length > 0 ? "web-action-required" : "npm-trust-failed",
400
+ };
401
+ const trustStatus =
402
+ trustCommand.ok && trustList.configured === true
403
+ ? "configured"
404
+ : urls.length > 0
405
+ ? "action-required"
406
+ : "failed";
407
+ const packageAfter = liveNpmPackageObservation(name, registry, resolvedCwd);
408
+ const packageVerified = packageAfter.exists === true;
409
+ const receipt = {
410
+ ...plan,
411
+ ok: trustStatus !== "failed" && packageVerified,
412
+ dryRun: false,
413
+ externalMutation: true,
414
+ errorCode:
415
+ trustStatus === "failed"
416
+ ? "npm-trust-failed"
417
+ : packageVerified
418
+ ? ""
419
+ : "npm-package-readback-failed",
420
+ package: {
421
+ ...plan.package,
422
+ existsAfter: packageAfter.exists,
423
+ observedVersionAfter: packageAfter.version,
424
+ readbackStatus: packageAfter.status,
425
+ },
426
+ publish: {
427
+ ...plan.publish,
428
+ status: publishStatus,
429
+ },
430
+ trust: {
431
+ status: trustStatus,
432
+ urls,
433
+ expectedPublisher,
434
+ exactBinding: trustList.exactBinding === true,
435
+ publishers: trustList.publishers,
436
+ },
437
+ nextActions:
438
+ trustStatus === "configured" && packageVerified
439
+ ? [
440
+ {
441
+ id: "paper-preflight",
442
+ command: "buildchain paper preflight --json",
443
+ description:
444
+ "Verify package existence and Trusted Publisher binding from live read-only sources.",
445
+ },
446
+ ]
447
+ : trustStatus === "action-required" && packageVerified
448
+ ? [
449
+ {
450
+ id: "complete-npm-web-action",
451
+ command: "",
452
+ description:
453
+ "Open the exact npm URL returned below, complete the web step, then rerun preflight.",
454
+ urls,
455
+ },
456
+ ]
457
+ : !packageVerified
458
+ ? [
459
+ {
460
+ id: "verify-npm-package-readback",
461
+ command: `npm view ${name} version --json --registry=${registry}`,
462
+ description:
463
+ "The mutation returned but the official registry did not prove package existence; do not infer success.",
464
+ },
465
+ ]
466
+ : [
467
+ {
468
+ id: "retry-npm-trust",
469
+ command: `buildchain paper bootstrap npm --execute --confirm-public-package ${name} --json`,
470
+ description:
471
+ "The package exists; retry only the idempotent Trusted Publisher configuration path.",
472
+ },
473
+ ],
474
+ };
475
+ receipt.receipts = [
476
+ writePaperReceipt(resolvedCwd, PAPER_PATHS.npmBootstrap, receipt),
477
+ ];
478
+ if (
479
+ packageVerified &&
480
+ (trustStatus === "configured" || trustStatus === "action-required")
481
+ ) {
482
+ receipt.receipts.push(
483
+ writePaperReceipt(resolvedCwd, PAPER_PATHS.npmTrust, receipt),
484
+ );
485
+ }
486
+ return receipt;
487
+ } finally {
488
+ fs.rmSync(tempRoot, { recursive: true, force: true });
489
+ }
490
+ }
491
+
492
+ export { executePaperNpmBootstrap };