@kungfu-tech/buildchain 2.8.15 → 2.8.16-alpha.2

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
@@ -1,16 +1,16 @@
1
1
  # Buildchain
2
2
 
3
- [![Verify](https://github.com/kungfu-systems/buildchain/actions/workflows/verify.yml/badge.svg?branch=dev%2Fv2%2Fv2.8)](https://github.com/kungfu-systems/buildchain/actions/workflows/verify.yml)
4
- [![Release Gate](https://github.com/kungfu-systems/buildchain/actions/workflows/buildchain-ref-promotion.yml/badge.svg)](https://github.com/kungfu-systems/buildchain/actions/workflows/buildchain-ref-promotion.yml)
5
- [![npm latest](https://img.shields.io/npm/v/%40kungfu-tech%2Fbuildchain/latest?label=npm%20latest)](https://www.npmjs.com/package/@kungfu-tech/buildchain)
6
- [![npm alpha](https://img.shields.io/npm/v/%40kungfu-tech%2Fbuildchain/alpha?label=npm%20alpha)](https://www.npmjs.com/package/@kungfu-tech/buildchain?activeTab=versions)
7
- [![GitHub Release](https://img.shields.io/github/v/release/kungfu-systems/buildchain?label=release)](https://github.com/kungfu-systems/buildchain/releases)
8
- [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
9
- [![KFD-1](https://img.shields.io/badge/KFD--1-contract%20world-2ea44f.svg)](docs/release-passport.md#kfd-1-contract-world-release-gate)
10
- [![KFD-2](https://img.shields.io/badge/KFD--2-trust%20passport-0969da.svg)](docs/release-passport.md#kfd-2-release-trust-passport-audit)
11
- [![KFD-3](https://img.shields.io/badge/KFD--3-collaboration%20interface-8250df.svg)](docs/release-passport.md#kfd-3-collaboration-interface-release-gate)
12
- ![Status: Stable](https://img.shields.io/badge/status-stable-brightgreen.svg)
13
- ![Platforms: macOS | Linux | Windows](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey.svg)
3
+ <!-- buildchain:badges:start -->
4
+ [![KFD-1: passed](https://img.shields.io/badge/KFD--1-contract%20world%20passed-2ea44f.svg)](https://github.com/kungfu-systems/buildchain/releases/latest/download/buildchain.release.json)
5
+ [![KFD-2: passed](https://img.shields.io/badge/KFD--2-trust%20passport%20passed-2ea44f.svg)](https://github.com/kungfu-systems/buildchain/releases/latest/download/buildchain.release.json)
6
+ [![KFD-3: passed](https://img.shields.io/badge/KFD--3-collaboration%20interface%20passed-2ea44f.svg)](https://github.com/kungfu-systems/buildchain/releases/latest/download/buildchain.release.json)
7
+ [![Release Passport: passed](https://img.shields.io/badge/release%20passport-passed-2ea44f.svg)](https://github.com/kungfu-systems/buildchain/releases/latest/download/buildchain.release.json)
8
+ [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-0969da.svg)](https://github.com/kungfu-systems/buildchain/blob/HEAD/LICENSE)
9
+ [![Platform: macOS | Linux | Windows](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-6e7781.svg)](https://github.com/kungfu-systems/buildchain/releases/latest/download/buildchain.release.json)
10
+ [![Verify](https://github.com/kungfu-systems/buildchain/actions/workflows/verify.yml/badge.svg)](https://github.com/kungfu-systems/buildchain/actions/workflows/verify.yml)
11
+ [![Buildchain Ref Promotion](https://github.com/kungfu-systems/buildchain/actions/workflows/buildchain-ref-promotion.yml/badge.svg)](https://github.com/kungfu-systems/buildchain/actions/workflows/buildchain-ref-promotion.yml)
12
+ [![Binary Distribution](https://github.com/kungfu-systems/buildchain/actions/workflows/binary-distribution.yml/badge.svg)](https://github.com/kungfu-systems/buildchain/actions/workflows/binary-distribution.yml)
13
+ <!-- buildchain:badges:end -->
14
14
 
15
15
  Buildchain Release Passport is a mature product release record for artifacts
16
16
  that users or agents depend on.
@@ -97,6 +97,14 @@ const report = verifyBuildchainLogEvents({
97
97
  The package also ships `dist/site/` as the Buildchain-owned fact source for
98
98
  `buildchain.libkungfu.dev`.
99
99
 
100
+ Repositories can also generate README status badges from Buildchain-owned facts
101
+ instead of hand-maintaining badge Markdown:
102
+
103
+ ```bash
104
+ buildchain badges readme --check
105
+ buildchain badges readme --write
106
+ ```
107
+
100
108
  ## Project Governance
101
109
 
102
110
  - [`LICENSE-POLICY.md`](LICENSE-POLICY.md) explains the Apache-2.0 project
@@ -30,6 +30,18 @@ import {
30
30
  explainArtifactPassport,
31
31
  verifyArtifactPassport,
32
32
  } from "../packages/core/artifact-passport.js";
33
+ import {
34
+ checkReadmeBadgeBlock,
35
+ collectReadmeBadgeFacts,
36
+ readReadme,
37
+ updateReadmeBadgeBlock,
38
+ } from "../packages/core/readme-badges.js";
39
+ import {
40
+ checkHomebrewTap,
41
+ collectHomebrewTapFacts,
42
+ renderHomebrewFormula,
43
+ updateHomebrewTap,
44
+ } from "../packages/core/homebrew.js";
33
45
  import {
34
46
  BUILDCHAIN_PROCESS_SAMPLE_REPORT_CONTRACT,
35
47
  formatDiagnosticsSummaryTable,
@@ -115,6 +127,9 @@ function usage() {
115
127
  buildchain web-surface ...
116
128
  buildchain infra-contract ...
117
129
  buildchain release-propagation <plan|write-lock> ...
130
+ buildchain badges readme [--cwd <dir>] [--readme <path>] [--check] [--write] [--json]
131
+ buildchain homebrew update-formula --package <name> --release-passport <file-or-url> [--write] [--json]
132
+ buildchain homebrew check [--cwd <dir>] [--package <name>] [--release-passport <file-or-url>] [--json]
118
133
  buildchain publish-source <lock|manifest|verify-lock|verify-channel-ref|validate-anchored-release> ...
119
134
  buildchain build-contract ...
120
135
 
@@ -277,6 +292,131 @@ function writeJsonFile(filePath, value) {
277
292
  return filePath;
278
293
  }
279
294
 
295
+ async function runReadmeBadgesCli(args = []) {
296
+ 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]");
299
+ }
300
+ const effectiveArgs = surface ? [surface, ...badgeArgs] : badgeArgs;
301
+ const cwd = path.resolve(readFlag(effectiveArgs, "cwd", process.cwd()));
302
+ const readmePath = readFlag(effectiveArgs, "readme", "README.md");
303
+ const facts = await collectReadmeBadgeFacts({ cwd });
304
+ if (readBooleanFlag(effectiveArgs, "json") && !readBooleanFlag(effectiveArgs, "check") && !readBooleanFlag(effectiveArgs, "write")) {
305
+ printJson(facts);
306
+ return;
307
+ }
308
+ const readmeText = readReadme({ cwd, readmePath });
309
+ if (!readmeText) {
310
+ throw new Error(`README not found: ${path.join(cwd, readmePath)}`);
311
+ }
312
+ const check = checkReadmeBadgeBlock({ readmeText, facts });
313
+ if (readBooleanFlag(effectiveArgs, "write")) {
314
+ const next = updateReadmeBadgeBlock({ readmeText, facts });
315
+ fs.writeFileSync(path.join(cwd, readmePath), next);
316
+ const result = {
317
+ schemaVersion: 1,
318
+ contract: "kungfu-buildchain-readme-badge-write",
319
+ ok: true,
320
+ changed: next !== readmeText,
321
+ readmePath,
322
+ facts,
323
+ };
324
+ if (readBooleanFlag(effectiveArgs, "json")) {
325
+ printJson(result);
326
+ } else {
327
+ process.stdout.write(`buildchain badges readme: ${result.changed ? "updated" : "current"}\n`);
328
+ }
329
+ return;
330
+ }
331
+ if (readBooleanFlag(effectiveArgs, "check")) {
332
+ if (readBooleanFlag(effectiveArgs, "json")) {
333
+ printJson(check);
334
+ } else {
335
+ process.stdout.write(`buildchain badges readme: ${check.ok ? "ok" : "failed"}\n`);
336
+ if (!check.ok) {
337
+ process.stdout.write(`${check.message}\n`);
338
+ }
339
+ }
340
+ if (!check.ok) {
341
+ process.exitCode = 1;
342
+ }
343
+ return;
344
+ }
345
+ printJson(facts);
346
+ }
347
+
348
+ async function runHomebrewCli(args = []) {
349
+ const [subcommand = "", ...homebrewArgs] = args;
350
+ const cwd = path.resolve(readFlag(homebrewArgs, "cwd", process.cwd()));
351
+ const packageName = readFlag(homebrewArgs, "package", "buildchain");
352
+ const releasePassport = readFlag(homebrewArgs, "release-passport", "");
353
+ const manifestPath = readFlag(homebrewArgs, "manifest", "tap-manifest.json");
354
+ const formulaPath = readFlag(homebrewArgs, "formula", "");
355
+ const json = readBooleanFlag(homebrewArgs, "json");
356
+ if (subcommand === "update-formula") {
357
+ if (!releasePassport) {
358
+ throw new Error("buildchain homebrew update-formula requires --release-passport <file-or-url>");
359
+ }
360
+ if (readBooleanFlag(homebrewArgs, "write")) {
361
+ const result = await updateHomebrewTap({
362
+ cwd,
363
+ packageName,
364
+ releasePassport,
365
+ manifestPath,
366
+ formulaPath,
367
+ write: true,
368
+ });
369
+ if (json) {
370
+ printJson(result);
371
+ } else {
372
+ process.stdout.write(`buildchain homebrew update-formula: wrote ${result.written.join(", ")}\n`);
373
+ }
374
+ return;
375
+ }
376
+ const facts = await collectHomebrewTapFacts({
377
+ cwd,
378
+ packageName,
379
+ releasePassport,
380
+ manifestPath,
381
+ formulaPath,
382
+ });
383
+ if (json) {
384
+ printJson({
385
+ schemaVersion: 1,
386
+ contract: "kungfu-buildchain-homebrew-formula-render",
387
+ facts,
388
+ formula: renderHomebrewFormula(facts),
389
+ manifest: facts.manifestProjection,
390
+ });
391
+ } else {
392
+ process.stdout.write(renderHomebrewFormula(facts));
393
+ }
394
+ return;
395
+ }
396
+ if (subcommand === "check") {
397
+ const report = await checkHomebrewTap({
398
+ cwd,
399
+ packageName,
400
+ releasePassport,
401
+ manifestPath,
402
+ formulaPath,
403
+ });
404
+ if (json) {
405
+ printJson(report);
406
+ } else {
407
+ process.stdout.write(`buildchain homebrew check: ${report.ok ? "ok" : "failed"}\n`);
408
+ for (const check of report.checks) {
409
+ process.stdout.write(`- ${check.status}: ${check.id}: ${check.message}\n`);
410
+ }
411
+ }
412
+ if (!report.ok) {
413
+ process.exitCode = 1;
414
+ }
415
+ return;
416
+ }
417
+ throw new Error("usage: buildchain homebrew <update-formula|check> ...");
418
+ }
419
+
280
420
  function appendJsonLine(filePath, value) {
281
421
  if (!filePath) {
282
422
  return "";
@@ -951,6 +1091,16 @@ async function main(argv = process.argv.slice(2)) {
951
1091
  return;
952
1092
  }
953
1093
 
1094
+ if (command === "badges") {
1095
+ await runReadmeBadgesCli(args);
1096
+ return;
1097
+ }
1098
+
1099
+ if (command === "homebrew") {
1100
+ await runHomebrewCli(args);
1101
+ return;
1102
+ }
1103
+
954
1104
  if (command === "build-contract") {
955
1105
  runScript("resolve-build-contract.mjs", args);
956
1106
  return;
@@ -4,7 +4,7 @@
4
4
  "product": {
5
5
  "name": "Buildchain",
6
6
  "package": "@kungfu-tech/buildchain",
7
- "version": "2.8.15",
7
+ "version": "2.8.16-alpha.2",
8
8
  "repository": "https://github.com/kungfu-systems/buildchain"
9
9
  },
10
10
  "majorLine": "v2",
@@ -134,7 +134,7 @@
134
134
  "breaking contract drift fails closed before rendering, deployment, or release publication"
135
135
  ],
136
136
  "breakingDigest": "sha256:82ee63cb336e40d832dfff4a1c5e6cbfa221a4fc8b2359990033bc931bffc43a",
137
- "auditDigest": "sha256:5416c9f4112bf24e7cef556f792034842252f65dcf9e8adf338ddc85a5137ada"
137
+ "auditDigest": "sha256:8de5899084cd0eebc93f5ac549b73c5ff313ac43067875d08b4ca8607d81fbf8"
138
138
  },
139
139
  {
140
140
  "contractVersion": 1,
@@ -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:79520e72824eb0245446f516fe6abe9faab0ec247c6d6cec7ac5fd62ab1f48ee"
238
+ "auditDigest": "sha256:e4a79237c0363b60fe084393068f6bc7da526bb9c5912b60d747b75364506b32"
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:79520e72824eb0245446f516fe6abe9faab0ec247c6d6cec7ac5fd62ab1f48ee"
287
+ "auditDigest": "sha256:e4a79237c0363b60fe084393068f6bc7da526bb9c5912b60d747b75364506b32"
288
288
  },
289
289
  {
290
290
  "contractVersion": 1,
@@ -331,16 +331,88 @@
331
331
  "optionalInputs": [
332
332
  "validate",
333
333
  "lifecycle",
334
+ "badges readme",
335
+ "homebrew update-formula",
336
+ "homebrew check",
334
337
  "collect github-release",
335
338
  "verify release-passport",
336
339
  "release-propagation",
337
340
  "infra-contract"
338
341
  ],
339
342
  "guarantees": [
340
- "CLI commands are stable within the major line unless the contract major changes"
343
+ "CLI commands are stable within the major line unless the contract major changes",
344
+ "README badge block checks and writes are generated from machine-readable repository facts"
341
345
  ],
342
- "breakingDigest": "sha256:097db3e67509bedda8c6548bf1edfbfcf57f7b5510520b6a7b7e078d7ec087c8",
343
- "auditDigest": "sha256:1f4b07ac623517209dbdee2992f94d95f7ee96e8f35f13ef620dad8da9d2a6e0"
346
+ "breakingDigest": "sha256:90a73892b2d6c214048448d5f45df75639bdf7b7e8fefd9c596e04b087407bcc",
347
+ "auditDigest": "sha256:b7cd109f1c81166fb912eced4b6d9aaa838ac537242197efd221e209da638d79"
348
+ },
349
+ {
350
+ "contractVersion": 1,
351
+ "stability": "stable",
352
+ "additiveChanges": "optional inputs, optional outputs, diagnostics, and documentation may be added within the same major line",
353
+ "id": "homebrew-distribution-index",
354
+ "kind": "node-api",
355
+ "path": "packages/core/homebrew.js",
356
+ "requiredInputs": [
357
+ "upstream release passport"
358
+ ],
359
+ "requiredOutputs": [
360
+ "kungfu-buildchain-homebrew-tap-facts",
361
+ "kungfu-buildchain-homebrew-tap-manifest",
362
+ "Formula/*.rb"
363
+ ],
364
+ "breakingDefaults": {
365
+ "projectType": "distribution-index",
366
+ "tapManifest": "tap-manifest.json",
367
+ "kfdPassedSource": "verified upstream release passport"
368
+ },
369
+ "optionalInputs": [
370
+ "buildchain.toml [project] type=distribution-index",
371
+ "Formula path",
372
+ "manifest path",
373
+ "release passport URL or local path"
374
+ ],
375
+ "guarantees": [
376
+ "Formula metadata is a deterministic projection of upstream release passport evidence",
377
+ "tap-manifest.json is checked against upstream version, URLs, SHA-256 digests, and KFD status",
378
+ "KFD passed claims fail closed unless the upstream release passport verifies the corresponding section",
379
+ "CLI and JavaScript callers use the same Node API implementation"
380
+ ],
381
+ "breakingDigest": "sha256:148c0387ff4cea76433bbde80cd9d77c5aa67e1a29856ced33e4d819366f2213",
382
+ "auditDigest": "sha256:0e978219bd6fca754d80a616d538d5825b116eec78b65857bbe5063b8c84d933"
383
+ },
384
+ {
385
+ "contractVersion": 1,
386
+ "stability": "stable",
387
+ "additiveChanges": "optional inputs, optional outputs, diagnostics, and documentation may be added within the same major line",
388
+ "id": "readme-badge-facts",
389
+ "kind": "node-api",
390
+ "path": "packages/core/readme-badges.js",
391
+ "requiredInputs": [
392
+ "repository checkout"
393
+ ],
394
+ "requiredOutputs": [
395
+ "kungfu-buildchain-readme-badge-facts"
396
+ ],
397
+ "breakingDefaults": {
398
+ "markerStart": "<!-- buildchain:badges:start -->",
399
+ "markerEnd": "<!-- buildchain:badges:end -->",
400
+ "kfdPassedSource": "verified repository-owned release passport"
401
+ },
402
+ "optionalInputs": [
403
+ "buildchain.toml [badges]",
404
+ "release passport URL or local path",
405
+ "workflow file list",
406
+ "platform declarations"
407
+ ],
408
+ "guarantees": [
409
+ "README badge Markdown is a deterministic projection of badge facts",
410
+ "KFD passed badges require the repository's own verified release passport section",
411
+ "unreleased repositories downgrade KFD status to explicit non-passed declarations",
412
+ "CLI and JavaScript callers use the same Node API implementation"
413
+ ],
414
+ "breakingDigest": "sha256:bcd72ad6dfba8013c96f8b2f7b0a307d2e7713972a1219348f0d5ecc493939a0",
415
+ "auditDigest": "sha256:a3400b0083430782d4fda283b21d308327eaed969053aa5b88a8b946bf83d4b3"
344
416
  },
345
417
  {
346
418
  "contractVersion": 1,
@@ -362,7 +434,7 @@
362
434
  "manual entries carry source file digests so downstream sites and agents can detect stale hand-written documentation"
363
435
  ],
364
436
  "breakingDigest": "sha256:7d0d2819e3a3e72989d9c57b5efe9d0bc0a79bc0f2c82a0c7b9d6c5a211a91f2",
365
- "auditDigest": "sha256:fd6753b3d3cd7561cd5f137f78fafa70ad7a6cc014b9f5c021c12e835c8a7a60"
437
+ "auditDigest": "sha256:77b5234de4d1ac60b8291e63b21562cdf88c1ab33a369e1f0cccb1e75a62e492"
366
438
  },
367
439
  {
368
440
  "contractVersion": 1,
@@ -384,9 +456,9 @@
384
456
  "agents can discover supported Node APIs without importing internal file paths"
385
457
  ],
386
458
  "breakingDigest": "sha256:48f925608d3e2131d90936b07dc2a30341204cae3e6e785c0f77d61ad755c945",
387
- "auditDigest": "sha256:8002cc53fb052c49e519cf2466d41b9f76a6241bcc8354520fad5121a7b78065"
459
+ "auditDigest": "sha256:587d0f465af8e3f1d871e469601999f57ac4911f3a84973fc6910b2db7555667"
388
460
  }
389
461
  ],
390
- "compatibilityDigest": "sha256:85e27de8d34ceac1652d9374697ea5a1a7a08666d2ba7ae377b9afdd14e2ca1f",
391
- "contractDigest": "sha256:3a7e7b0ae8accb3c830791de83b8af310305b198949adcbd1483526b5abb1b17"
462
+ "compatibilityDigest": "sha256:407d6d5ee6a96a34d2cc30db9ac64cf4b1819ab6d77bd7a57a07a124f22101ca",
463
+ "contractDigest": "sha256:df8e273c2225f1564d77e4089e5d0128746df3c121c9ccfa85082fff1a616ecb"
392
464
  }