@kungfu-tech/buildchain 2.11.0 → 2.11.1-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.
@@ -7,7 +7,7 @@
7
7
  "workflowCount": 36,
8
8
  "actionCount": 4,
9
9
  "sitePageCount": 45,
10
- "docCommandRefCount": 227,
10
+ "docCommandRefCount": 229,
11
11
  "failureCount": 0
12
12
  },
13
13
  "enumerated": {
@@ -70,7 +70,7 @@
70
70
  {
71
71
  "id": "explain-artifact",
72
72
  "source": "bin/buildchain.mjs",
73
- "usage": "buildchain explain artifact <subject> [--passport <file-or-url>] [--for human|agent] [--json]"
73
+ "usage": "buildchain explain artifact <subject> [--passport <file-or-url>] [--npm-registry <url>] [--for human|agent] [--json]"
74
74
  },
75
75
  {
76
76
  "id": "explain-release",
@@ -120,7 +120,7 @@
120
120
  {
121
121
  "id": "inspect-artifact",
122
122
  "source": "bin/buildchain.mjs",
123
- "usage": "buildchain inspect artifact <subject> [--passport <file-or-url>] [--json]"
123
+ "usage": "buildchain inspect artifact <subject> [--passport <file-or-url>] [--npm-registry <url>] [--json]"
124
124
  },
125
125
  {
126
126
  "id": "inspect-release",
@@ -1937,6 +1937,11 @@
1937
1937
  "path": "docs/kfd-support.md",
1938
1938
  "command": "buildchain kfd migrate-layout --write"
1939
1939
  },
1940
+ {
1941
+ "id": "kfd-migrate-layout",
1942
+ "path": "docs/kfd-support.md",
1943
+ "command": "buildchain kfd migrate-layout --write"
1944
+ },
1940
1945
  {
1941
1946
  "id": "kfd-schema-list",
1942
1947
  "path": "docs/cli.md",
@@ -2332,6 +2337,11 @@
2332
2337
  "path": "docs/cli.md",
2333
2338
  "command": "buildchain verify artifact"
2334
2339
  },
2340
+ {
2341
+ "id": "verify-artifact",
2342
+ "path": "docs/cli.md",
2343
+ "command": "buildchain verify artifact npm"
2344
+ },
2335
2345
  {
2336
2346
  "id": "verify-artifact",
2337
2347
  "path": "docs/release-passport.md",
@@ -2438,9 +2448,9 @@
2438
2448
  "cliRegistryPath": "dist/site/cli-registry.json",
2439
2449
  "workflowRegistryPath": "dist/site/workflow-registry.json",
2440
2450
  "pageRegistryPath": "dist/site/page-registry.json",
2441
- "cliRegistryDigest": "1f7e1f7707a089f067175030fde6712b69ceece3df1b811eb542b0b4c8c1d4a9",
2451
+ "cliRegistryDigest": "53833f92021caa7cc5feaff5d21f38b0a77317ace11a43795be180d1dec3699f",
2442
2452
  "workflowRegistryDigest": "67572429a83124370b9ffd46f56923aa2b252873c9624ded39a26675fb0ee815",
2443
- "pageRegistryDigest": "eca33e2ed1e0dbffe8ce7f8f5ee5b4fdc34ef7b2daad7091a2be192ab70b80db"
2453
+ "pageRegistryDigest": "14b3d852445462c23c9c48d786844353a8c3e2764092323fabe60dcab9e39aae"
2444
2454
  },
2445
2455
  "comparison": {
2446
2456
  "missingCliRegistry": [],
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "contract": "kungfu-buildchain-site-manifest",
4
- "generatedAt": "2026-07-09T04:23:24.659Z",
5
- "publishedAt": "2026-07-09T04:23:24.659Z",
4
+ "generatedAt": "2026-07-09T10:17:37.497Z",
5
+ "publishedAt": "2026-07-09T10:17:37.497Z",
6
6
  "reproducible": true,
7
7
  "timestampPolicy": "ci-injected",
8
8
  "deterministicInputs": [
@@ -19,7 +19,7 @@
19
19
  "declared Buildchain surface manifest contract"
20
20
  ],
21
21
  "sourceDateEpoch": "0",
22
- "sourceRevision": "290544db8afeaa9c1af5220adabeff932764fab7",
22
+ "sourceRevision": "85d3b04ebed5b161f019095bdb5ff5e18d4513db",
23
23
  "timestampPolicyDetails": {
24
24
  "contract": "kungfu-buildchain-surface-timestamp-policy",
25
25
  "timestampFields": [
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "package": {
39
39
  "name": "@kungfu-tech/buildchain",
40
- "version": "2.11.0",
40
+ "version": "2.11.1-alpha.2",
41
41
  "versionSource": "package.json#version"
42
42
  },
43
43
  "entrypoint": "buildchain-site.json",
@@ -53,7 +53,7 @@
53
53
  "path": "docs/MAP.md",
54
54
  "plane": "use",
55
55
  "exists": true,
56
- "digest": "sha256:a57f131080254b3f7a0950b5bdd580b256ecb29047a0e1ee16e8385d61a44b81"
56
+ "digest": "sha256:795464d3d84af5698b19a26821dbd16040c258b708e070daaaba6d55e6ad81f7"
57
57
  },
58
58
  {
59
59
  "id": "install",
@@ -69,7 +69,7 @@
69
69
  "path": "docs/release-passport.md",
70
70
  "plane": "verify",
71
71
  "exists": true,
72
- "digest": "sha256:332f058d9a016cc31c709a3447a56dc43ffd0c5e6cdbcd15f9a62f61bb16eb15"
72
+ "digest": "sha256:f278f148e36f508f7217ad0e41501fa1cf5fe4d0a54d81dfbab867b3d35465c7"
73
73
  },
74
74
  {
75
75
  "id": "release-candidate",
@@ -77,7 +77,7 @@
77
77
  "path": "docs/release-candidate.md",
78
78
  "plane": "verify",
79
79
  "exists": true,
80
- "digest": "sha256:391f14569c7d2a43dd9986c6a29462d674a77338dac6a4ac89c79a4c3d6c4947"
80
+ "digest": "sha256:841d6f3281ba6dfe80527e4f149807bdbd05d41f9e94afe1c446fcd6d29e307c"
81
81
  },
82
82
  {
83
83
  "id": "release-propagation",
@@ -173,7 +173,7 @@
173
173
  "path": "docs/cli.md",
174
174
  "plane": "use",
175
175
  "exists": true,
176
- "digest": "sha256:d77b7d5e4006e952235f6d68daff01bcc4cf87d81b874c57e447caabdaf0acaa"
176
+ "digest": "sha256:4b31f7ff5330cde8ab32b237f533c7af76463cce570d67dd14669c3a14c83c84"
177
177
  },
178
178
  {
179
179
  "id": "build-facts",
@@ -189,7 +189,7 @@
189
189
  "path": "docs/kfd-support.md",
190
190
  "plane": "verify",
191
191
  "exists": true,
192
- "digest": "sha256:4bcf5d1ce63555072130eae90c739555b11658d1d796a3fcea770b90841c4afd"
192
+ "digest": "sha256:ce1bbf5c085a69649ee2e6ae76a52419eef94304e59efc0d0dcd4466c714709e"
193
193
  },
194
194
  {
195
195
  "id": "lifecycle-protocol",
package/docs/MAP.md CHANGED
@@ -42,7 +42,7 @@ workflow, action, and Node API export also carries a `capabilityGroup`,
42
42
  | Capability-grouped KFD navigation | `dist/site/capability-registry.json`, `dist/site/page-registry.json`, `dist/site/manual-registry.json`, `dist/site/cli-registry.json`, `dist/site/node-api-registry.json` | this map, [`site-bundle-contract.md`](site-bundle-contract.md), [`kfd-support.md`](kfd-support.md) |
43
43
  | KFD-1 / KFD-2 / KFD-3 release-passport gates | `dist/site/kfd-claims.json`, `dist/site/buildchain-contract.json`, `dist/site/artifact-schemas.json` | [`release-passport.md`](release-passport.md) |
44
44
  | KFD-3 public surface reverse audit | `dist/site/public-surface-audit.json`, `dist/site/cli-registry.json`, `dist/site/workflow-registry.json`, `dist/site/page-registry.json` | [`cli.md`](cli.md), [`site-bundle-contract.md`](site-bundle-contract.md) |
45
- | KFD-1 / KFD-2 / KFD-3 first-class CLI and Node API | `.buildchain/kfd/kfd-3-surfaces.json`, `dist/site/kfd-claims.json`, `buildchain.release.json`, KFD schemas from `@kungfu-tech/kfd` | [`kfd-support.md`](kfd-support.md), [`cli.md`](cli.md#commands) |
45
+ | KFD-1 / KFD-2 / KFD-3 first-class CLI and Node API | `.buildchain/kfd/kfd-3/surfaces.json`, `dist/site/kfd-claims.json`, `buildchain.release.json`, KFD schemas from `@kungfu-tech/kfd` | [`kfd-support.md`](kfd-support.md), [`cli.md`](cli.md#commands) |
46
46
  | Floating `@v2` drift detection and compatibility issues | `dist/site/buildchain-contract.json` | [`reusable-build-surface.md`](reusable-build-surface.md#floating-ref-contract-lock) |
47
47
  | npm publish transactions, evidence, dist-tags, and recovery | `dist/site/release-model.json`, `dist/site/artifact-schemas.json` | [`publish-transaction.md`](publish-transaction.md) |
48
48
  | Git/source/version/module/product build facts | `dist/site/node-api-registry.json`, `dist/site/cli-registry.json`, `kungfu-buildchain-module-build-facts`, `kungfu-buildchain-product-build-facts` | [`build-facts.md`](build-facts.md) |
package/docs/cli.md CHANGED
@@ -104,7 +104,10 @@ Supported presets:
104
104
  plans by default, and only configured `[infra.commands]` hooks can execute.
105
105
  - `--type publication-artifact` for papers, reports, specifications, and other
106
106
  publication repositories that produce PDFs, metadata, source bundles, and
107
- site-consumable manifests without becoming web-surface repositories.
107
+ site-consumable manifests without becoming web-surface repositories. The
108
+ scaffold uses Buildchain's pinned
109
+ `ghcr.io/kungfu-systems/build-images/latex-pdf-builder:v1.2.0` toolchain for
110
+ LaTeX PDF builds.
108
111
  - `--type distribution-index` for Homebrew taps and other index repositories
109
112
  whose files are projections of upstream release passport evidence.
110
113
  - `--type anchored-package` for packages whose version is anchored to an
@@ -219,7 +222,7 @@ buildchain kfd schema show kfd-3 --json
219
222
  buildchain kfd 3 detect --kind node-api --kind cli --json
220
223
  buildchain kfd 3 register node-api --product Buildchain
221
224
  buildchain kfd 3 audit --json
222
- buildchain kfd 3 witness --kind prebuild --output .buildchain/kfd-3/collaboration-interface.prebuild.json
225
+ buildchain kfd 3 witness --kind prebuild --output .buildchain/kfd/kfd-3/collaboration-interface.prebuild.json
223
226
  buildchain kfd 3 query buildchain --json
224
227
  buildchain kfd 4 schema --json
225
228
  ```
@@ -400,7 +403,7 @@ The command writes `.buildchain/publication/publication-artifact.json`,
400
403
  and, when `[publication.archive]` is configured,
401
404
  `.buildchain/publication/publication-registry.json` by default. See
402
405
  [`publication-artifacts.md`](publication-artifacts.md) for the repository
403
- contract and reusable workflow.
406
+ contract, pinned LaTeX builder, and reusable workflow.
404
407
 
405
408
  Generate, check, or update the managed README badge block:
406
409
 
@@ -477,9 +480,9 @@ buildchain collect github-release \
477
480
  --platform-manifest-json .buildchain/artifacts/darwin-arm64/manifest.json \
478
481
  --platform-manifest-json .buildchain/artifacts/win32-x64/manifest.json \
479
482
  --dist-tag-evidence-json .buildchain/release-evidence/v2.3.2/dist-tag-evidence.json \
480
- --kfd-1-witness-json .buildchain/kfd-1/contract-world.witness.json \
481
- --kfd-2-claim-json .buildchain/kfd-2/release-claims.json \
482
- --kfd-3-prebuild-witness-json .buildchain/kfd-3/collaboration-interface.prebuild.json \
483
+ --kfd-1-witness-json .buildchain/kfd/kfd-1/contract-world.witness.json \
484
+ --kfd-2-claim-json .buildchain/kfd/kfd-2/release-claims.json \
485
+ --kfd-3-prebuild-witness-json .buildchain/kfd/kfd-3/collaboration-interface.prebuild.json \
483
486
  --kfd-3-artifact-verify-cmd "kungfu agent verify --json" \
484
487
  --release-extra-json '{"channel":"release","targetRef":"release/v2/v2.3"}' \
485
488
  --output-dir .buildchain/release-passport
@@ -576,6 +579,10 @@ Verify a published artifact by subject:
576
579
  buildchain verify artifact ./Kungfu-2.8.0-windows-x64.exe
577
580
  buildchain inspect artifact ./Kungfu-2.8.0-windows-x64.exe --json
578
581
  buildchain explain artifact ./Kungfu-2.8.0-windows-x64.exe --for agent --json
582
+ buildchain verify artifact npm:@kungfu-tech/libnode@22.22.3-kf.3-alpha.18 \
583
+ --repository kungfu-systems/libnode \
584
+ --tag v22.22.3-kf.3-alpha.18 \
585
+ --json
579
586
  ```
580
587
 
581
588
  `verify artifact` computes or obtains the subject digest, discovers the
@@ -583,6 +590,10 @@ detached release passport, verifies the passport, then requires that the
583
590
  subject digest appears in the passport's release assets, package set, publish
584
591
  evidence, or artifact evidence. Outcomes are explicit: `pass`, `fail`, or
585
592
  `unverifiable`. A filename is only a hint; trust comes from digest equality.
593
+ For `npm:<name>@<version>` subjects, Buildchain resolves `dist.integrity` from
594
+ the npm registry before matching passport evidence. Use `--npm-registry <url>`
595
+ to verify packages from a custom registry; otherwise Buildchain uses
596
+ `npm_config_registry` or `https://registry.npmjs.org/`.
586
597
 
587
598
  Discovery is fail-closed and ordered:
588
599
 
@@ -10,14 +10,16 @@ facts, not as README prose. The machine-readable sources are:
10
10
  - `buildchain.release.json` for release-specific KFD-1, KFD-2, and KFD-3
11
11
  passport results;
12
12
  - `.buildchain/buildchain.toml` for repository-owned Buildchain configuration;
13
- - `.buildchain/kfd/kfd-3-surfaces.json` for product-owned KFD-3 surface
13
+ - `.buildchain/kfd/kfd-3/surfaces.json` for product-owned KFD-3 surface
14
14
  registration;
15
15
  - `.buildchain/contract-lock.json` for accepted floating runtime contracts.
16
16
 
17
17
  Buildchain still reads the legacy root files `buildchain.toml`,
18
- `buildchain.contract-lock.json`, and `buildchain.kfd3.json` so existing
19
- consumers do not break, but new repositories should keep repo-owned Buildchain
20
- files under `.buildchain/`.
18
+ `buildchain.contract-lock.json`, `buildchain.kfd3.json`, and the historical
19
+ `.buildchain/kfd/kfd-3-surfaces.json` registry so existing consumers can run
20
+ `buildchain kfd migrate-layout --write`. New repositories should keep
21
+ repo-owned Buildchain files under `.buildchain/`, with all KFD evidence under
22
+ `.buildchain/kfd/`.
21
23
 
22
24
  ## Unified Namespace
23
25
 
@@ -145,9 +147,9 @@ package = "@kungfu-tech/kfd"
145
147
  repository = "kungfu-systems/kfd"
146
148
  evidence = [
147
149
  "package:kfd.release.json",
148
- "package:.buildchain/kfd-1/contract-world.witness.json",
149
- "package:.buildchain/kfd-2/public-release-trust.claim.json",
150
- "package:.buildchain/kfd-3/collaboration-interface.json",
150
+ "package:.buildchain/kfd/kfd-1/contract-world.witness.json",
151
+ "package:.buildchain/kfd/kfd-2/release-claims.json",
152
+ "package:.buildchain/kfd/kfd-3/collaboration-interface.json",
151
153
  "package:standards.json",
152
154
  ]
153
155
  ```
@@ -251,7 +253,7 @@ KFD-3 surface registration uses three states.
251
253
  | State | Meaning |
252
254
  | --- | --- |
253
255
  | `detected` | Buildchain found a candidate public surface from package metadata, wheel metadata, CLI bins, binary artifacts, docs, or site bundle facts. |
254
- | `declared` | The product owner accepted that candidate into `.buildchain/kfd/kfd-3-surfaces.json`. |
256
+ | `declared` | The product owner accepted that candidate into `.buildchain/kfd/kfd-3/surfaces.json`. |
255
257
  | `enforced` | The product has promoted a declared surface to a hard release boundary. Missing enforced surfaces fail release verification. |
256
258
 
257
259
  Detection does not silently become product intent. `register` is the boundary
@@ -298,7 +300,7 @@ Generate a witness for release passport collection:
298
300
  ```bash
299
301
  buildchain kfd 3 witness \
300
302
  --kind prebuild \
301
- --output .buildchain/kfd-3/collaboration-interface.prebuild.json
303
+ --output .buildchain/kfd/kfd-3/collaboration-interface.prebuild.json
302
304
  ```
303
305
 
304
306
  Query capability facts for agents or downstream sites:
@@ -46,8 +46,8 @@ registry_path = ".buildchain/publication/publication-registry.json"
46
46
 
47
47
  [publication.toolchain]
48
48
  type = "latex-docker"
49
- image = "ghcr.io/kungfu-systems/latex"
50
- digest = "sha256:0000000000000000000000000000000000000000000000000000000000000000"
49
+ image = "ghcr.io/kungfu-systems/build-images/latex-pdf-builder"
50
+ digest = "sha256:c20f3809e96836c1c78e97c76939d12f1de3fed0ea9b7c40c43332ec2ea480f8"
51
51
  command = "latexmk -pdf -outdir=_build paper/main.tex"
52
52
 
53
53
  [lifecycle.build]
@@ -82,11 +82,14 @@ if PDF, source bundle, route, metadata, or toolchain evidence changes for an
82
82
  existing version, Buildchain fails before the registry is rewritten.
83
83
 
84
84
  `publication.toolchain` makes the source-to-PDF transformation part of the
85
- machine-readable contract. `latex-docker` is the preferred LaTeX profile: the
86
- workflow pulls the declared image by digest and runs the declared command in
87
- that pinned container. `custom-command` remains available for compatibility,
88
- but the passport records it as lower trust because Buildchain can record the
89
- command boundary without proving the compiler or LaTeX distribution digest.
85
+ machine-readable contract. `latex-docker` is the preferred LaTeX profile. The
86
+ Buildchain paper scaffold and reusable workflow default to
87
+ `ghcr.io/kungfu-systems/build-images/latex-pdf-builder:v1.2.0`, pinned by the
88
+ digest above. The workflow pulls the declared image by digest and runs the
89
+ declared command in that pinned container. `custom-command` remains available
90
+ for compatibility, but the passport records it as lower trust because
91
+ Buildchain can record the command boundary without proving the compiler or
92
+ LaTeX distribution digest.
90
93
 
91
94
  ## Reusable Workflow
92
95
 
@@ -109,8 +112,8 @@ The workflow:
109
112
  any paper build runs;
110
113
  - resolves the declared publication toolchain from `[publication.toolchain]` or
111
114
  workflow inputs;
112
- - for `latex-docker`, pulls the pinned image digest and runs the declared
113
- command in the container;
115
+ - for `latex-docker`, pulls the pinned build-images LaTeX builder digest and
116
+ runs the declared command in the container;
114
117
  - for `custom-command`, runs the declared command and records the lower-trust
115
118
  boundary in the passport;
116
119
  - runs the verify command;
@@ -105,9 +105,9 @@ jobs:
105
105
  with:
106
106
  channel: alpha
107
107
  artifact-name: libnode
108
- release-passport-kfd-1-witness-jsons: .buildchain/kfd-1/standard-contract.witness.json
109
- release-passport-kfd-2-claim-jsons: .buildchain/kfd-2/release-claims.json
110
- release-passport-kfd-3-prebuild-witness-jsons: .buildchain/kfd-3/collaboration-interface.prebuild.json
108
+ release-passport-kfd-1-witness-jsons: .buildchain/kfd/kfd-1/standard-contract.witness.json
109
+ release-passport-kfd-2-claim-jsons: .buildchain/kfd/kfd-2/release-claims.json
110
+ release-passport-kfd-3-prebuild-witness-jsons: .buildchain/kfd/kfd-3/collaboration-interface.prebuild.json
111
111
  release-passport-kfd-3-artifact-verify-command: kungfu agent verify --json
112
112
  ```
113
113
 
@@ -109,8 +109,8 @@ buildchain collect github-release \
109
109
  --platform-manifest-json .buildchain/artifacts/darwin-arm64/manifest.json \
110
110
  --platform-manifest-json .buildchain/artifacts/win32-x64/manifest.json \
111
111
  --dist-tag-evidence-json .buildchain/release-evidence/v2.2.0/dist-tag-evidence.json \
112
- --kfd-1-witness-json .buildchain/kfd-1/contract-world.witness.json \
113
- --kfd-2-claim-json .buildchain/kfd-2/release-claims.json \
112
+ --kfd-1-witness-json .buildchain/kfd/kfd-1/contract-world.witness.json \
113
+ --kfd-2-claim-json .buildchain/kfd/kfd-2/release-claims.json \
114
114
  --output-dir .buildchain/release-passport
115
115
  ```
116
116
 
@@ -279,7 +279,7 @@ pre-build witness:
279
279
 
280
280
  ```bash
281
281
  kungfu sdk collaboration-interface witness --json \
282
- > .buildchain/kfd-3/collaboration-interface.prebuild.json
282
+ > .buildchain/kfd/kfd-3/collaboration-interface.prebuild.json
283
283
  ```
284
284
 
285
285
  That witness must contain, or point to, the product-owned KFD-3 collaboration
@@ -292,7 +292,7 @@ either as a JSON file or a command:
292
292
 
293
293
  ```bash
294
294
  buildchain collect github-release \
295
- --kfd-3-prebuild-witness-json .buildchain/kfd-3/collaboration-interface.prebuild.json \
295
+ --kfd-3-prebuild-witness-json .buildchain/kfd/kfd-3/collaboration-interface.prebuild.json \
296
296
  --kfd-3-artifact-verify-cmd "kungfu agent verify --json"
297
297
  ```
298
298
 
@@ -376,6 +376,11 @@ appears in the passport's artifacts, package set, publish evidence, or artifact
376
376
  evidence. The command returns `pass`, `fail`, or `unverifiable`; missing
377
377
  passports and digest mismatches fail closed.
378
378
 
379
+ For npm subjects, Buildchain treats the registry as the package digest source:
380
+ `npm:<name>@<version>` resolves `dist.integrity` and matches it against
381
+ `packageSet.main.digest`, `packageSet.platforms[].digest`, and publish evidence.
382
+ Use `--npm-registry <url>` when the package comes from a non-default registry.
383
+
379
384
  Discovery is ordered and auditable:
380
385
 
381
386
  1. explicit `--passport`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "2.11.0",
3
+ "version": "2.11.1-alpha.2",
4
4
  "private": false,
5
5
  "description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
6
6
  "repository": "https://github.com/kungfu-systems/buildchain",
@@ -69,7 +69,9 @@ writeBuildFacts({ fact, output: ".buildchain/facts/native-core.json" });
69
69
  Publication repositories can produce site-consumable paper/report facts without
70
70
  becoming web-surface repositories. When `[publication.archive]` is configured,
71
71
  the same API also maintains the append-only publication registry used by site
72
- repositories for latest and historical version pages:
72
+ repositories for latest and historical version pages. The preferred
73
+ `latex-docker` toolchain records the pinned build-images LaTeX builder digest in
74
+ the publication artifact passport:
73
75
 
74
76
  ```js
75
77
  import { writePublicationArtifact } from "@kungfu-tech/buildchain/publication-artifact";
@@ -8,6 +8,7 @@ import { readJsonFromLocation, sha256File, verifyReleasePassport } from "./relea
8
8
  export const ARTIFACT_VERIFICATION_CONTRACT = "kungfu-buildchain-artifact-verification";
9
9
  export const ARTIFACT_PASSPORT_POINTER_CONTRACT = "kungfu-buildchain-artifact-passport-pointer";
10
10
  export const ARTIFACT_PASSPORT_LOCATOR_CONTRACT = "kungfu-buildchain-artifact-passport-locator";
11
+ export const DEFAULT_NPM_REGISTRY_BASE_URL = "https://registry.npmjs.org/";
11
12
 
12
13
  function optionalString(value) {
13
14
  return value === undefined || value === null ? "" : String(value);
@@ -118,6 +119,45 @@ function parseNpmSubject(subject) {
118
119
  return { name: spec.slice(0, atIndex), version: spec.slice(atIndex + 1) };
119
120
  }
120
121
 
122
+ function normalizeNpmRegistryBaseUrl(value = "") {
123
+ const registry = optionalString(value || process.env.npm_config_registry || DEFAULT_NPM_REGISTRY_BASE_URL).trim();
124
+ return registry.endsWith("/") ? registry : `${registry}/`;
125
+ }
126
+
127
+ function npmRegistryPackageMetadataUrl(name, registryBaseUrl = "") {
128
+ return new URL(encodeURIComponent(name), normalizeNpmRegistryBaseUrl(registryBaseUrl)).toString();
129
+ }
130
+
131
+ async function resolveNpmSubjectDigest({ name, version, registryBaseUrl = "" } = {}) {
132
+ if (!name || !version) {
133
+ return { status: "skipped", reason: "missing-name-or-version" };
134
+ }
135
+ const metadataUrl = npmRegistryPackageMetadataUrl(name, registryBaseUrl);
136
+ const metadata = await readJsonFromLocation(metadataUrl);
137
+ const versionMetadata = metadata?.versions?.[version];
138
+ if (!versionMetadata) {
139
+ return {
140
+ status: "missing",
141
+ reason: "version-not-found",
142
+ registry: normalizeNpmRegistryBaseUrl(registryBaseUrl),
143
+ metadataUrl,
144
+ };
145
+ }
146
+ const integrity = optionalString(versionMetadata.dist?.integrity);
147
+ const shasum = optionalString(versionMetadata.dist?.shasum);
148
+ const digest = integrity || (shasum ? `sha1:${shasum}` : "");
149
+ return {
150
+ status: digest ? "resolved" : "missing",
151
+ reason: digest ? "" : "dist-integrity-missing",
152
+ registry: normalizeNpmRegistryBaseUrl(registryBaseUrl),
153
+ metadataUrl,
154
+ digest,
155
+ integrity,
156
+ shasum,
157
+ tarball: optionalString(versionMetadata.dist?.tarball),
158
+ };
159
+ }
160
+
121
161
  function parseGitHubReleaseSubject(subject) {
122
162
  const value = subject.replace(/^github-release:/, "");
123
163
  const match = value.match(/^([^/]+\/[^@/]+)@([^/]+)\/(.+)$/);
@@ -328,6 +368,7 @@ export async function resolveArtifactSubject(subject, {
328
368
  cwd = process.cwd(),
329
369
  subjectDigest = "",
330
370
  subjectKind = "",
371
+ npmRegistryBaseUrl = "",
331
372
  } = {}) {
332
373
  const input = optionalString(subject).trim();
333
374
  if (!input) {
@@ -335,12 +376,38 @@ export async function resolveArtifactSubject(subject, {
335
376
  }
336
377
  if (/^npm:/i.test(input)) {
337
378
  const parsed = parseNpmSubject(input);
379
+ let npmDigest = {};
380
+ if (!subjectDigest) {
381
+ try {
382
+ npmDigest = await resolveNpmSubjectDigest({
383
+ name: parsed.name,
384
+ version: parsed.version,
385
+ registryBaseUrl: npmRegistryBaseUrl,
386
+ });
387
+ } catch (error) {
388
+ npmDigest = {
389
+ status: "error",
390
+ registry: normalizeNpmRegistryBaseUrl(npmRegistryBaseUrl),
391
+ error: error.message,
392
+ };
393
+ }
394
+ }
395
+ const digest = subjectDigest || npmDigest.digest || "";
338
396
  return {
339
397
  input,
340
398
  kind: subjectKind || "npm-package",
341
399
  name: parsed.name,
342
400
  version: parsed.version,
343
- digest: subjectDigest,
401
+ digest,
402
+ integrity: npmDigest.integrity || (digest.startsWith("sha512-") ? digest : ""),
403
+ shasum: npmDigest.shasum || "",
404
+ registry: npmDigest.registry || normalizeNpmRegistryBaseUrl(npmRegistryBaseUrl),
405
+ npm: {
406
+ digestResolution: npmDigest.status || (subjectDigest ? "provided" : "skipped"),
407
+ metadataUrl: npmDigest.metadataUrl || "",
408
+ tarball: npmDigest.tarball || "",
409
+ error: npmDigest.error || "",
410
+ },
344
411
  localPath: "",
345
412
  };
346
413
  }
@@ -640,8 +707,9 @@ export async function verifyArtifactPassport({
640
707
  githubReleaseBaseUrl = "",
641
708
  subjectDigest = "",
642
709
  subjectKind = "",
710
+ npmRegistryBaseUrl = "",
643
711
  } = {}) {
644
- const resolvedSubject = await resolveArtifactSubject(subject, { cwd, subjectDigest, subjectKind });
712
+ const resolvedSubject = await resolveArtifactSubject(subject, { cwd, subjectDigest, subjectKind, npmRegistryBaseUrl });
645
713
  const issues = [];
646
714
  if (resolvedSubject.missing) {
647
715
  issues.push(issue("error", "subject.missing", "artifact subject does not exist locally", { subject: resolvedSubject.input }));
@@ -6,8 +6,27 @@ export const BUILDCHAIN_CONFIG_PATH = ".buildchain/buildchain.toml";
6
6
  export const LEGACY_BUILDCHAIN_CONFIG_PATH = "buildchain.toml";
7
7
  export const BUILDCHAIN_CONTRACT_LOCK_PATH = ".buildchain/contract-lock.json";
8
8
  export const LEGACY_BUILDCHAIN_CONTRACT_LOCK_PATH = "buildchain.contract-lock.json";
9
- export const BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH = ".buildchain/kfd/kfd-3-surfaces.json";
9
+ export const BUILDCHAIN_KFD_ROOT = ".buildchain/kfd";
10
+ export const BUILDCHAIN_KFD1_DIR = ".buildchain/kfd/kfd-1";
11
+ export const BUILDCHAIN_KFD2_DIR = ".buildchain/kfd/kfd-2";
12
+ export const BUILDCHAIN_KFD3_DIR = ".buildchain/kfd/kfd-3";
13
+ export const BUILDCHAIN_KFD4_DIR = ".buildchain/kfd/kfd-4";
14
+ export const BUILDCHAIN_KFD1_CONTRACT_WORLD_WITNESS_PATH = ".buildchain/kfd/kfd-1/contract-world.witness.json";
15
+ export const BUILDCHAIN_KFD1_RELEASE_GATE_PATH = ".buildchain/kfd/kfd-1/release-gate.json";
16
+ export const BUILDCHAIN_KFD1_VERIFY_RESULT_PATH = ".buildchain/kfd/kfd-1/verify-result.json";
17
+ export const BUILDCHAIN_KFD2_RELEASE_CLAIMS_PATH = ".buildchain/kfd/kfd-2/release-claims.json";
18
+ export const BUILDCHAIN_KFD2_CLAIM_ARGS_PATH = ".buildchain/kfd/kfd-2/buildchain-claim-args.txt";
19
+ export const BUILDCHAIN_KFD2_CLAIMS_DIR = ".buildchain/kfd/kfd-2/claims";
20
+ export const BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH = ".buildchain/kfd/kfd-3/surfaces.json";
21
+ export const BUILDCHAIN_KFD3_COLLABORATION_INTERFACE_PATH = ".buildchain/kfd/kfd-3/collaboration-interface.json";
22
+ export const BUILDCHAIN_KFD3_PREBUILD_WITNESS_PATH = ".buildchain/kfd/kfd-3/collaboration-interface.prebuild.json";
23
+ export const BUILDCHAIN_KFD3_ARTIFACT_WITNESS_PATH = ".buildchain/kfd/kfd-3/collaboration-interface.artifact.json";
24
+ export const BUILDCHAIN_KFD3_CAPABILITY_QUERY_PATH = ".buildchain/kfd/kfd-3/capability-query.json";
10
25
  export const LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH = "buildchain.kfd3.json";
26
+ export const LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATHS = Object.freeze([
27
+ ".buildchain/kfd/kfd-3-surfaces.json",
28
+ LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
29
+ ]);
11
30
  export const BUILDCHAIN_RELEASE_PASSPORT_PATH = ".buildchain/release-passport/buildchain.release.json";
12
31
  export const LEGACY_BUILDCHAIN_RELEASE_PASSPORT_PATH = "buildchain.release.json";
13
32
 
@@ -59,7 +78,7 @@ export function resolveBuildchainContractLockPath(cwd = process.cwd()) {
59
78
  export function resolveKfd3SurfaceRegistryPath(cwd = process.cwd()) {
60
79
  return firstExistingRepoPath(cwd, [
61
80
  BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
62
- LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
81
+ ...LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATHS,
63
82
  ]);
64
83
  }
65
84
 
@@ -87,7 +106,79 @@ export function discoverBuildchainRepoFiles(cwd = process.cwd()) {
87
106
  {
88
107
  kind: "kfd-3-surface-registry",
89
108
  canonical: BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
90
- legacy: LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
109
+ legacy: LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATHS,
110
+ tracked: true,
111
+ },
112
+ {
113
+ kind: "kfd-1-contract-world-witness",
114
+ canonical: BUILDCHAIN_KFD1_CONTRACT_WORLD_WITNESS_PATH,
115
+ legacy: [
116
+ ".buildchain/kfd-1/contract-world.witness.json",
117
+ ".buildchain/kfd/buildchain-kfd-1-witness.json",
118
+ ],
119
+ tracked: true,
120
+ },
121
+ {
122
+ kind: "kfd-1-release-gate",
123
+ canonical: BUILDCHAIN_KFD1_RELEASE_GATE_PATH,
124
+ legacy: [".buildchain/kfd-1/release-gate.json"],
125
+ tracked: true,
126
+ },
127
+ {
128
+ kind: "kfd-1-verify-result",
129
+ canonical: BUILDCHAIN_KFD1_VERIFY_RESULT_PATH,
130
+ legacy: [".buildchain/kfd-1/verify-result.json"],
131
+ tracked: false,
132
+ },
133
+ {
134
+ kind: "kfd-2-release-claims",
135
+ canonical: BUILDCHAIN_KFD2_RELEASE_CLAIMS_PATH,
136
+ legacy: [
137
+ ".buildchain/kfd-2/release-claims.json",
138
+ ".buildchain/kfd-2/public-release-trust.claim.json",
139
+ ],
140
+ tracked: true,
141
+ },
142
+ {
143
+ kind: "kfd-2-claim-args",
144
+ canonical: BUILDCHAIN_KFD2_CLAIM_ARGS_PATH,
145
+ legacy: [".buildchain/kfd-2/buildchain-claim-args.txt"],
146
+ tracked: true,
147
+ },
148
+ {
149
+ kind: "kfd-2-claims",
150
+ canonical: BUILDCHAIN_KFD2_CLAIMS_DIR,
151
+ legacy: [".buildchain/kfd/kfd-2-claims", ".buildchain/kfd-2/claims"],
152
+ tracked: false,
153
+ },
154
+ {
155
+ kind: "kfd-3-collaboration-interface",
156
+ canonical: BUILDCHAIN_KFD3_COLLABORATION_INTERFACE_PATH,
157
+ legacy: [".buildchain/kfd-3/collaboration-interface.json"],
158
+ tracked: true,
159
+ },
160
+ {
161
+ kind: "kfd-3-prebuild-witness",
162
+ canonical: BUILDCHAIN_KFD3_PREBUILD_WITNESS_PATH,
163
+ legacy: [
164
+ ".buildchain/kfd-3/collaboration-interface.prebuild.json",
165
+ ".buildchain/kfd/buildchain-kfd-3-prebuild-witness.json",
166
+ ],
167
+ tracked: true,
168
+ },
169
+ {
170
+ kind: "kfd-3-artifact-witness",
171
+ canonical: BUILDCHAIN_KFD3_ARTIFACT_WITNESS_PATH,
172
+ legacy: [
173
+ ".buildchain/kfd-3/collaboration-interface.artifact.json",
174
+ ".buildchain/kfd/buildchain-kfd-3-artifact-witness.json",
175
+ ],
176
+ tracked: true,
177
+ },
178
+ {
179
+ kind: "kfd-3-capability-query",
180
+ canonical: BUILDCHAIN_KFD3_CAPABILITY_QUERY_PATH,
181
+ legacy: [".buildchain/kfd-3/capability-query.json"],
91
182
  tracked: true,
92
183
  },
93
184
  {
@@ -99,12 +190,16 @@ export function discoverBuildchainRepoFiles(cwd = process.cwd()) {
99
190
  ];
100
191
  return files.map((entry) => {
101
192
  const canonicalExists = fs.existsSync(repoPath(cwd, entry.canonical));
102
- const legacyExists = fs.existsSync(repoPath(cwd, entry.legacy));
193
+ const legacyPaths = Array.isArray(entry.legacy) ? entry.legacy : [entry.legacy].filter(Boolean);
194
+ const existingLegacyPaths = legacyPaths.filter((legacy) => fs.existsSync(repoPath(cwd, legacy)));
195
+ const legacyExists = existingLegacyPaths.length > 0;
103
196
  return {
104
197
  ...entry,
198
+ legacy: legacyPaths,
105
199
  canonicalExists,
106
200
  legacyExists,
107
- activePath: canonicalExists ? entry.canonical : legacyExists ? entry.legacy : entry.canonical,
201
+ existingLegacyPaths,
202
+ activePath: canonicalExists ? entry.canonical : legacyExists ? existingLegacyPaths[0] : entry.canonical,
108
203
  migrationNeeded: !canonicalExists && legacyExists,
109
204
  };
110
205
  });
@@ -114,12 +209,12 @@ export function planBuildchainLayoutMigration({ cwd = process.cwd() } = {}) {
114
209
  const entries = discoverBuildchainRepoFiles(cwd);
115
210
  const moves = entries
116
211
  .filter((entry) => entry.migrationNeeded)
117
- .map((entry) => ({
212
+ .flatMap((entry) => entry.existingLegacyPaths.map((legacy) => ({
118
213
  kind: entry.kind,
119
- from: entry.legacy,
214
+ from: legacy,
120
215
  to: entry.canonical,
121
216
  tracked: entry.tracked,
122
- }));
217
+ })));
123
218
  return {
124
219
  schemaVersion: 1,
125
220
  contract: "kungfu-buildchain-repository-layout-migration",