@kungfu-tech/buildchain 2.8.17 → 2.9.0

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 CHANGED
@@ -101,6 +101,8 @@ Repositories can also generate README status badges from Buildchain-owned facts
101
101
  instead of hand-maintaining badge Markdown:
102
102
 
103
103
  ```bash
104
+ buildchain badges bundle --check
105
+ buildchain badges bundle --write
104
106
  buildchain badges readme --check
105
107
  buildchain badges readme --write
106
108
  ```
@@ -31,9 +31,12 @@ import {
31
31
  verifyArtifactPassport,
32
32
  } from "../packages/core/artifact-passport.js";
33
33
  import {
34
+ checkBadgeBundleBlock,
34
35
  checkReadmeBadgeBlock,
36
+ collectBadgeBundleFacts,
35
37
  collectReadmeBadgeFacts,
36
38
  readReadme,
39
+ updateBadgeBundleBlock,
37
40
  updateReadmeBadgeBlock,
38
41
  } from "../packages/core/readme-badges.js";
39
42
  import {
@@ -50,6 +53,13 @@ import {
50
53
  summarizeProcessSamples,
51
54
  validateAnchoredPackageRelease,
52
55
  } from "../packages/core/diagnostics.js";
56
+ import {
57
+ aggregateBuildFacts,
58
+ collectModuleBuildFacts,
59
+ verifyBuildFacts,
60
+ writeBuildFacts,
61
+ writeKungfuBuildInfoProjection,
62
+ } from "../packages/core/build-facts.js";
53
63
 
54
64
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
55
65
  const embeddedPackageVersion = process.env.BUILDCHAIN_EMBEDDED_PACKAGE_VERSION || "";
@@ -86,6 +96,7 @@ function usage() {
86
96
  [--anchor-manifest-json <json-or-path>]
87
97
  [--impact-json <json-or-path>]
88
98
  [--build-summary-json <json-or-path>]
99
+ [--build-facts-json <json-or-path>]...
89
100
  [--platform-manifest-json <json-or-path>]...
90
101
  [--dist-tag-evidence-json <json-or-path>]
91
102
  [--kfd-1-witness-json <json-or-path>]...
@@ -116,6 +127,13 @@ function usage() {
116
127
  buildchain log summary [--path <jsonl>] [--json]
117
128
  buildchain diagnostics summary <diagnostics.json>... [--artifact <file>]...
118
129
  [--output <file>] [--json]
130
+ buildchain facts module [--cwd <dir>] [--module <id>] [--module-root <path>]
131
+ [--version-source <id>] [--output <file>]
132
+ [--output-path <path>]... [--legacy-kungfu-buildinfo <file>] [--json]
133
+ buildchain facts aggregate [--cwd <dir>] [--product <id>]
134
+ [--module-fact <file>]... [--artifact <path>]...
135
+ [--output <file>] [--json]
136
+ buildchain facts verify [--cwd <dir>] --fact <file> [--json]
119
137
  buildchain sample process-tree [--interval-ms <n>] [--label <name>]
120
138
  [--output <jsonl>] [--summary-output <json>]
121
139
  [--requested-parallelism <n>] [--json]
@@ -128,6 +146,7 @@ function usage() {
128
146
  buildchain infra-contract ...
129
147
  buildchain release-propagation <plan|write-lock> ...
130
148
  buildchain badges readme [--cwd <dir>] [--readme <path>] [--check] [--write] [--json]
149
+ buildchain badges bundle [--cwd <dir>] [--readme <path>] [--claims <csv>] [--check] [--write] [--json]
131
150
  buildchain homebrew update-formula --package <name> --release-passport <file-or-url> [--write] [--json]
132
151
  buildchain homebrew check [--cwd <dir>] [--package <name>] [--release-passport <file-or-url>] [--json]
133
152
  buildchain publish-source <lock|manifest|verify-lock|verify-channel-ref|validate-anchored-release> ...
@@ -294,13 +313,20 @@ function writeJsonFile(filePath, value) {
294
313
 
295
314
  async function runReadmeBadgesCli(args = []) {
296
315
  const [subcommand = "", surface = "", ...badgeArgs] = args;
297
- if (subcommand !== "readme" || (surface && surface.startsWith("--") === false)) {
298
- throw new Error("usage: buildchain badges readme [--cwd <dir>] [--readme <path>] [--check] [--write] [--json]");
316
+ if (!["readme", "bundle"].includes(subcommand) || (surface && surface.startsWith("--") === false)) {
317
+ throw new Error("usage: buildchain badges <readme|bundle> [--cwd <dir>] [--readme <path>] [--claims <csv>] [--check] [--write] [--json]");
299
318
  }
300
319
  const effectiveArgs = surface ? [surface, ...badgeArgs] : badgeArgs;
301
320
  const cwd = path.resolve(readFlag(effectiveArgs, "cwd", process.cwd()));
302
321
  const readmePath = readFlag(effectiveArgs, "readme", "README.md");
303
- const facts = await collectReadmeBadgeFacts({ cwd });
322
+ const claims = readFlag(effectiveArgs, "claims", "");
323
+ const isBundle = subcommand === "bundle";
324
+ const facts = isBundle
325
+ ? await collectBadgeBundleFacts({ cwd, claims })
326
+ : await collectReadmeBadgeFacts({ cwd });
327
+ const checkBlock = isBundle ? checkBadgeBundleBlock : checkReadmeBadgeBlock;
328
+ const updateBlock = isBundle ? updateBadgeBundleBlock : updateReadmeBadgeBlock;
329
+ const commandLabel = `buildchain badges ${subcommand}`;
304
330
  if (readBooleanFlag(effectiveArgs, "json") && !readBooleanFlag(effectiveArgs, "check") && !readBooleanFlag(effectiveArgs, "write")) {
305
331
  printJson(facts);
306
332
  return;
@@ -309,13 +335,13 @@ async function runReadmeBadgesCli(args = []) {
309
335
  if (!readmeText) {
310
336
  throw new Error(`README not found: ${path.join(cwd, readmePath)}`);
311
337
  }
312
- const check = checkReadmeBadgeBlock({ readmeText, facts });
338
+ const check = checkBlock({ readmeText, facts });
313
339
  if (readBooleanFlag(effectiveArgs, "write")) {
314
- const next = updateReadmeBadgeBlock({ readmeText, facts });
340
+ const next = updateBlock({ readmeText, facts });
315
341
  fs.writeFileSync(path.join(cwd, readmePath), next);
316
342
  const result = {
317
343
  schemaVersion: 1,
318
- contract: "kungfu-buildchain-readme-badge-write",
344
+ contract: isBundle ? "kungfu-buildchain-badge-bundle-write" : "kungfu-buildchain-readme-badge-write",
319
345
  ok: true,
320
346
  changed: next !== readmeText,
321
347
  readmePath,
@@ -324,7 +350,7 @@ async function runReadmeBadgesCli(args = []) {
324
350
  if (readBooleanFlag(effectiveArgs, "json")) {
325
351
  printJson(result);
326
352
  } else {
327
- process.stdout.write(`buildchain badges readme: ${result.changed ? "updated" : "current"}\n`);
353
+ process.stdout.write(`${commandLabel}: ${result.changed ? "updated" : "current"}\n`);
328
354
  }
329
355
  return;
330
356
  }
@@ -332,7 +358,7 @@ async function runReadmeBadgesCli(args = []) {
332
358
  if (readBooleanFlag(effectiveArgs, "json")) {
333
359
  printJson(check);
334
360
  } else {
335
- process.stdout.write(`buildchain badges readme: ${check.ok ? "ok" : "failed"}\n`);
361
+ process.stdout.write(`${commandLabel}: ${check.ok ? "ok" : "failed"}\n`);
336
362
  if (!check.ok) {
337
363
  process.stdout.write(`${check.message}\n`);
338
364
  }
@@ -417,6 +443,85 @@ async function runHomebrewCli(args = []) {
417
443
  throw new Error("usage: buildchain homebrew <update-formula|check> ...");
418
444
  }
419
445
 
446
+ async function runBuildFactsCli(args = []) {
447
+ const [subcommand = "", ...factArgs] = args;
448
+ const cwd = path.resolve(readFlag(factArgs, "cwd", process.cwd()));
449
+ if (subcommand === "module") {
450
+ const fact = collectModuleBuildFacts({
451
+ cwd,
452
+ moduleId: readFlag(factArgs, "module", ""),
453
+ moduleRoot: readFlag(factArgs, "module-root", ""),
454
+ versionSourceId: readFlag(factArgs, "version-source", ""),
455
+ outputs: readRepeatedFlag(factArgs, "output-path"),
456
+ lifecycle: readFlag(factArgs, "lifecycle", ""),
457
+ platform: readFlag(factArgs, "platform", "") || undefined,
458
+ });
459
+ const output = readFlag(factArgs, "output", "");
460
+ const writeResult = output ? writeBuildFacts({ cwd, fact, output }) : undefined;
461
+ const legacyOutput = readFlag(factArgs, "legacy-kungfu-buildinfo", "");
462
+ const legacyProjection = legacyOutput
463
+ ? writeKungfuBuildInfoProjection({ cwd, moduleFact: fact, output: legacyOutput })
464
+ : undefined;
465
+ const result = {
466
+ ...fact,
467
+ ...(writeResult ? { written: writeResult } : {}),
468
+ ...(legacyProjection ? { legacyProjection: { path: legacyProjection.path, digest: legacyProjection.digest } } : {}),
469
+ };
470
+ if (readBooleanFlag(factArgs, "json") || !output) {
471
+ printJson(result);
472
+ } else {
473
+ process.stdout.write(`buildchain facts module: ${fact.verification.ok ? "ok" : "failed"} ${writeResult.path}\n`);
474
+ }
475
+ if (!fact.verification.ok) {
476
+ process.exitCode = 1;
477
+ }
478
+ return;
479
+ }
480
+ if (subcommand === "aggregate") {
481
+ const fact = aggregateBuildFacts({
482
+ cwd,
483
+ productId: readFlag(factArgs, "product", ""),
484
+ moduleFacts: readRepeatedFlag(factArgs, "module-fact"),
485
+ artifacts: readRepeatedFlag(factArgs, "artifact"),
486
+ });
487
+ const output = readFlag(factArgs, "output", "");
488
+ const writeResult = output ? writeBuildFacts({ cwd, fact, output }) : undefined;
489
+ const result = {
490
+ ...fact,
491
+ ...(writeResult ? { written: writeResult } : {}),
492
+ };
493
+ if (readBooleanFlag(factArgs, "json") || !output) {
494
+ printJson(result);
495
+ } else {
496
+ process.stdout.write(`buildchain facts aggregate: ${fact.verification.ok ? "ok" : "failed"} ${writeResult.path}\n`);
497
+ }
498
+ if (!fact.verification.ok) {
499
+ process.exitCode = 1;
500
+ }
501
+ return;
502
+ }
503
+ if (subcommand === "verify") {
504
+ const factPath = readFlag(factArgs, "fact", "");
505
+ if (!factPath) {
506
+ throw new Error("usage: buildchain facts verify --fact <file>");
507
+ }
508
+ const result = verifyBuildFacts({ cwd, factPath });
509
+ if (readBooleanFlag(factArgs, "json")) {
510
+ printJson(result);
511
+ } else {
512
+ process.stdout.write(`buildchain facts verify: ${result.ok ? "ok" : "failed"}\n`);
513
+ for (const issue of result.issues) {
514
+ process.stdout.write(`- ${issue.level}: ${issue.id}: ${issue.message}\n`);
515
+ }
516
+ }
517
+ if (!result.ok) {
518
+ process.exitCode = 1;
519
+ }
520
+ return;
521
+ }
522
+ throw new Error("usage: buildchain facts <module|aggregate|verify> ...");
523
+ }
524
+
420
525
  function appendJsonLine(filePath, value) {
421
526
  if (!filePath) {
422
527
  return "";
@@ -697,6 +802,11 @@ async function main(argv = process.argv.slice(2)) {
697
802
  return;
698
803
  }
699
804
 
805
+ if (command === "facts") {
806
+ await runBuildFactsCli(args);
807
+ return;
808
+ }
809
+
700
810
  if (command === "sample") {
701
811
  const [subcommand = "", ...sampleArgs] = args;
702
812
  if (subcommand !== "process-tree") {
@@ -878,6 +988,7 @@ async function main(argv = process.argv.slice(2)) {
878
988
  anchorManifestJson: readFlag(collectArgs, "anchor-manifest-json", ""),
879
989
  impactJson: readFlag(collectArgs, "impact-json", ""),
880
990
  buildSummaryJson: readFlag(collectArgs, "build-summary-json", ""),
991
+ buildFactsJsons: readRepeatedFlag(collectArgs, "build-facts-json"),
881
992
  platformManifestJsons: readRepeatedFlag(collectArgs, "platform-manifest-json"),
882
993
  distTagEvidenceJson: readFlag(collectArgs, "dist-tag-evidence-json", ""),
883
994
  kfd1WitnessJsons: readRepeatedFlag(collectArgs, "kfd-1-witness-json"),
@@ -4,7 +4,7 @@
4
4
  "product": {
5
5
  "name": "Buildchain",
6
6
  "package": "@kungfu-tech/buildchain",
7
- "version": "2.8.17",
7
+ "version": "2.9.0",
8
8
  "repository": "https://github.com/kungfu-systems/buildchain"
9
9
  },
10
10
  "majorLine": "v2",
@@ -235,7 +235,7 @@
235
235
  "release-state SHA is recorded as a durable audit entrance"
236
236
  ],
237
237
  "breakingDigest": "sha256:b627e1b2ece9b6049517a942c5139e342e6077cdd3d8962d61cef8481b1f70ad",
238
- "auditDigest": "sha256:e4a79237c0363b60fe084393068f6bc7da526bb9c5912b60d747b75364506b32"
238
+ "auditDigest": "sha256:ce36cc21cfd3e0508a2a816292863dc2e11f19146b2624ef066fc9aaa4f4190e"
239
239
  },
240
240
  {
241
241
  "contractVersion": 1,
@@ -284,7 +284,7 @@
284
284
  "prose-only public claims downgrade the release trust passport audit"
285
285
  ],
286
286
  "breakingDigest": "sha256:f0b636eb925ddbf45ff1a8872454ab7b4dd98857cac12bb75217830130e62a16",
287
- "auditDigest": "sha256:e4a79237c0363b60fe084393068f6bc7da526bb9c5912b60d747b75364506b32"
287
+ "auditDigest": "sha256:ce36cc21cfd3e0508a2a816292863dc2e11f19146b2624ef066fc9aaa4f4190e"
288
288
  },
289
289
  {
290
290
  "contractVersion": 1,
@@ -344,7 +344,7 @@
344
344
  "README badge block checks and writes are generated from machine-readable repository facts"
345
345
  ],
346
346
  "breakingDigest": "sha256:90a73892b2d6c214048448d5f45df75639bdf7b7e8fefd9c596e04b087407bcc",
347
- "auditDigest": "sha256:b7cd109f1c81166fb912eced4b6d9aaa838ac537242197efd221e209da638d79"
347
+ "auditDigest": "sha256:114de9f5a2cd5602bec3ff7599aae1a09858ff53a96b562ebe542d501d37eb46"
348
348
  },
349
349
  {
350
350
  "contractVersion": 1,
@@ -412,7 +412,7 @@
412
412
  "CLI and JavaScript callers use the same Node API implementation"
413
413
  ],
414
414
  "breakingDigest": "sha256:bcd72ad6dfba8013c96f8b2f7b0a307d2e7713972a1219348f0d5ecc493939a0",
415
- "auditDigest": "sha256:35c42750bbdede7d85b71444d1d09cd6c7ce40ecd8868c86d869855764dad0c2"
415
+ "auditDigest": "sha256:3d4b61918f31a24de8fb11b15a9544df2c9696f6bd8c7efb1e373f0745cb3ce0"
416
416
  },
417
417
  {
418
418
  "contractVersion": 1,
@@ -434,7 +434,7 @@
434
434
  "manual entries carry source file digests so downstream sites and agents can detect stale hand-written documentation"
435
435
  ],
436
436
  "breakingDigest": "sha256:7d0d2819e3a3e72989d9c57b5efe9d0bc0a79bc0f2c82a0c7b9d6c5a211a91f2",
437
- "auditDigest": "sha256:f3bb661b2260d2be500d8707bdb01b623e8125cdb36e874dc217bc0873422b39"
437
+ "auditDigest": "sha256:cd21906acf183b9f5b456f7013581dd55e493b904551f00475cf6ea2f0030098"
438
438
  },
439
439
  {
440
440
  "contractVersion": 1,
@@ -456,9 +456,9 @@
456
456
  "agents can discover supported Node APIs without importing internal file paths"
457
457
  ],
458
458
  "breakingDigest": "sha256:48f925608d3e2131d90936b07dc2a30341204cae3e6e785c0f77d61ad755c945",
459
- "auditDigest": "sha256:b92a9b199a69ac78e55da9bc28e6bd2922233861b70205a2de45eed65cfc81c6"
459
+ "auditDigest": "sha256:10855957c6eac44c41c59518e1d1310e6efd735ed3b5e1eddff4f98296352717"
460
460
  }
461
461
  ],
462
462
  "compatibilityDigest": "sha256:407d6d5ee6a96a34d2cc30db9ac64cf4b1819ab6d77bd7a57a07a124f22101ca",
463
- "contractDigest": "sha256:590724458a59dfed521c876c24cedec43124409b4be79f4ce839ce26ce9f98de"
463
+ "contractDigest": "sha256:45c8a3198664e76e58ff881befcac450a7db6cfd6bffb5bcd3db747a895c551e"
464
464
  }