Skip to content

Commit 6efbb3b

Browse files
committed
feat: harden Registry lifecycle and reproduction
1 parent 050ab4e commit 6efbb3b

29 files changed

Lines changed: 2292 additions & 455 deletions

.github/workflows/ci.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,26 @@ jobs:
2020
name: Test
2121
runs-on: ubuntu-latest
2222
timeout-minutes: 45
23+
services:
24+
postgres:
25+
image: postgres:17-alpine
26+
env:
27+
POSTGRES_DB: cellscript_registry_test
28+
POSTGRES_USER: cellscript_test
29+
POSTGRES_PASSWORD: cellscript_test_password
30+
ports:
31+
- 5432:5432
32+
options: >-
33+
--health-cmd "pg_isready -U cellscript_test -d cellscript_registry_test"
34+
--health-interval 5s
35+
--health-timeout 5s
36+
--health-retries 10
2337
env:
2438
CARGO_INCREMENTAL: "0"
2539
CARGO_TARGET_DIR: /tmp/cellscript-ci-target
2640
CELLSCRIPT_BACKEND_SHAPE_REPORT: /tmp/cellscript-backend-shape/backend-shape-report.json
2741
CKB_SDK_RUST_REF: v5.1.0
42+
REGISTRY_TEST_DATABASE_URL: postgresql://cellscript_test:cellscript_test_password@127.0.0.1:5432/cellscript_registry_test
2843
steps:
2944
- name: Check out repository
3045
uses: actions/checkout@v4

CHANGELOG.md

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@
55
- Complete the Registry's generalized artifact and chain-evidence path. Rust,
66
C, JavaScript, and other CKB artifacts now keep explicit source, build,
77
deployment, TCB, and copy-only identities instead of being presented as
8-
CellScript dependencies. Reproducible profiles require two to sixteen
9-
distinct builder reports bound to the signed environment, source, recipe,
10-
executable, build log, and predecessor evidence before verification becomes
11-
`verified`; deployment is rejected until that evidence exists. Add
8+
CellScript dependencies. Reproducible profiles require P-256-signed reports
9+
from two to sixteen policy-approved builders spanning the configured minimum
10+
number of independent trust domains. Reports bind the signed environment,
11+
source, recipe, executable, build log, builder identity, and predecessor
12+
evidence before verification becomes `verified`; deployment is rejected
13+
until that evidence exists. Add `cellc artifact reproduction-report` and
1214
`cellc artifact reproduction-evidence`, wallet-ready mainnet commitment
13-
transaction intents, fixed Registry Type/attestor Lock configuration,
15+
transaction intents, fixed Registry Type/commitment Lock configuration,
1416
Type-Script-indexed `CSREGv1` scans, and scheduled lifecycle reconciliation
15-
that demotes spent attestations or stale deployment Cells without deleting
16-
historical evidence. The chain path is implemented but remains
17-
operationally disabled until the canonical mainnet Registry Type Script,
18-
CellDep, and attestor Lock are deployed and configured.
17+
that demotes spent commitments or stale deployment Cells without deleting
18+
historical evidence. Both Script code CellDeps must be live and sufficiently
19+
confirmed before the chain path becomes ready. The chain path is implemented
20+
but remains operationally disabled until the canonical mainnet Registry Type
21+
Script, commitment custody Lock, and both CellDeps are deployed and configured.
1922
- Harden the unified artifact Registry boundary: default discovery now hides
2023
pending/rejected releases and paginates by package coordinate; deployment
2124
records and admin recovery must match the immutable CKB `hash_type` and
@@ -53,9 +56,12 @@
5356
auth commands use `--wallet-signature`, with `--joyid-signature` retained as
5457
a visible compatibility alias, and the API adds the corresponding typed
5558
principal migration and signature verification. The compact chooser now
56-
preserves the complete official twelve-wallet CKB directory: compatible CCC
57-
signers connect directly, while the remaining wallets use the same verified
58-
external-signature handoff instead of disappearing from the UI. Every entry
59+
preserves the complete twelve-wallet CKB directory: compatible CCC CKB
60+
signers connect directly, while other entries are explicitly labelled as
61+
external links for importing a compatible `wallet-signature.json`; opening a
62+
link is never represented as a wallet connection. The browser checks the
63+
signature shape and principal binding before submission, while the API
64+
remains authoritative for cryptographic verification. Every entry
5965
now uses the corresponding official Nervos wallet-directory SVG rather than
6066
an autogenerated letter mark or a runtime favicon. The chooser header no
6167
longer reserves space for a hidden back control, so its title, explanatory
@@ -147,7 +153,7 @@
147153
version-addressed static JSON, and the website require both Edition 2026 and
148154
the separate compatibility-profile hash, with no fallback reader for
149155
incomplete entries. Generic admin status changes cannot manufacture
150-
`verified_build`, `deployed`, or `on_chain_attested` claims; those states
156+
`verified_build`, `deployed`, or `on_chain_committed` claims; those states
151157
require the ordered evidence-promotion path. See the
152158
[0.23 development release notes](docs/releases/CELLSCRIPT_0_23_RELEASE_NOTES.md).
153159
- Complete the native-tooling cleanup: neutralize migration-era identifiers,

audits/0.23-deep-dive.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ flowchart TD
487487
const adminAllowed = ["source_published", "indexed_pending", "verified_build",
488488
"deployed", "deprecated", "yanked", "quarantined"];
489489

490-
// 0.23: 5 个(verified_build / deployed / on_chain_attested 移除 admin 权限)
490+
// 0.23: 5 个(verified_build / deployed / on_chain_committed 移除 admin 权限)
491491
const adminAllowed = ["source_published", "indexed_pending",
492492
"deprecated", "yanked", "quarantined"];
493493
```
@@ -501,7 +501,7 @@ stateDiagram-v2
501501
source_published --> verified_build: 0.23 evidence endpoint
502502
indexed_pending --> verified_build: 0.22 任意 / 0.23 仅 evidence endpoint
503503
verified_build --> deployed: 0.22 任意 / 0.23 仅 evidence endpoint
504-
deployed --> on_chain_attested: 0.22 任意 / 0.23 仅 evidence endpoint
504+
deployed --> on_chain_committed: 0.22 任意 / 0.23 仅 evidence endpoint
505505
source_published --> deprecated: 0.22 + 0.23
506506
indexed_pending --> deprecated: 0.22 + 0.23
507507
source_published --> yanked: 0.22 + 0.23
@@ -513,9 +513,9 @@ stateDiagram-v2
513513
**0.23 状态机含义**
514514

515515
- ✅ admin API 仍可达:`source_published` / `indexed_pending` / `deprecated` / `yanked` / `quarantined`
516-
- ✅ generic admin API **不可伪造**`verified_build` / `deployed` / `on_chain_attested`
516+
- ✅ generic admin API **不可伪造**`verified_build` / `deployed` / `on_chain_committed`
517517
-`POST /v1/admin/packages/:namespace/:name/versions/:version/promote`
518-
已实现证据专用路径:`source_published|indexed_pending → verified_build → deployed → on_chain_attested`
518+
已实现证据专用路径:`source_published|indexed_pending → verified_build → deployed → on_chain_committed`
519519
- ✅ 每一步校验 `source_hash` / `manifest_hash` / `compatibility_profile_hash`;部署证据必须引用 verified-build evidence hash,链上证明必须引用 deployed evidence hash
520520
-`package_version_evidence` 持久化 hash-addressed evidence,静态版本 JSON 与公共 evidence read API 同步公开链条
521521

docs/CELLSCRIPT_PACKAGE_PROVENANCE_AND_DEPLOYMENT_IDENTITY.md

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -244,20 +244,22 @@ compiler version, and possibly type-id lineage.
244244
A deployment-bound package is what wallets and production builders should rely
245245
on when constructing real transactions.
246246

247-
**On-chain-attested package.** A deployment claim has an explicit JoyID-rooted
248-
attestation or chain-indexed record. This is a stronger statement about who made
249-
the deployment claim, but it still does not replace source, build, deployment,
250-
and live-chain verification.
247+
**On-chain-committed package.** A sufficiently confirmed live mainnet Cell
248+
commits the exact Registry release/deployment tuple under the configured
249+
Registry Type Script and custody Lock. This is a current discoverability and
250+
integrity statement, not an attestation of source quality or authorship. It does
251+
not replace source, build, deployment, and live-chain verification.
251252

252253
**Deprecated, yanked, or quarantined package.** Historical entries remain
253254
addressable for reproducibility, but default search and recommendation surfaces
254255
may suppress them. Quarantine is for abuse or high-risk packages; yanking is a
255256
maintainer action that preserves exact-pin warning metadata.
256257

257258
The same source package version may have zero, one, or many deployment
258-
bindings. For example, `amm@1.2.0` may start as a source-only package, later
259-
gain a CKB testnet deployment, then eventually a CKB mainnet deployment. These
260-
are separate deployment records attached to the same source/package identity,
259+
bindings. For example, `amm@1.2.0` may start as a source-only package and later
260+
gain one or more CKB mainnet deployment bindings. Local or private tooling may
261+
track testnet deployments separately, but the public Registry accepts only
262+
mainnet deployment evidence. These are separate deployment records attached to the same source/package identity,
261263
not separate source packages.
262264

263265
```
@@ -1197,7 +1199,7 @@ source_published -> direct URL and author dashboard visible
11971199
indexed_pending -> waiting for asynchronous verifier/indexer workers
11981200
verified_build -> build evidence accepted
11991201
deployed -> deployment facts attached and verified locally
1200-
on_chain_attested -> feature-gated JoyID/chain-backed deployment attestation
1202+
on_chain_committed -> sufficiently confirmed live Registry commitment Cell
12011203
deprecated/yanked -> historical entry retained, default resolution suppressed
12021204
quarantined -> direct URL retained, default search suppressed
12031205
```
@@ -1730,9 +1732,9 @@ registry admission authority.
17301732
|---|---|
17311733
| JoyID-rooted publisher identity | `cellc auth capability create --principal-id <principal_id> --scope publish:ns/pkg --expires 90d --json > capability-payload.json` plus `cellc auth capability submit --payload capability-payload.json --joyid-signature joyid-signature.json` uses the CCC-backed JoyID flow, records `principal_type = joyid_ckb`, binds `principal_id` to a local publisher credential, and stores that credential in the OS keychain |
17321734
| Scoped publisher credentials | Capability-style signing key with namespace/package/action scopes, expiry, revocation, nonce/origin checks, and CI-safe delegation |
1733-
| Namespace/package ACL | Namespace owners, package maintainers, yanking authority, attestation authority, maintainer rotation, and source-location update permissions |
1735+
| Namespace/package ACL | Namespace owners, package maintainers, yanking authority, commitment authority, maintainer rotation, and source-location update permissions |
17341736
| Abuse controls | Separate static read path from write API; WAF/rate limits/body caps/hash dedup/bounded queues/quarantine/cooldown; fee/bond rules remain later policy hooks |
1735-
| Entry visibility state machine | `source_published` -> `indexed_pending` -> `verified_build` -> `deployed` -> `on_chain_attested`; `deprecated`/`yanked`/`quarantined` suppress default search without deleting history |
1737+
| Entry visibility state machine | `source_published` -> `indexed_pending` -> `verified_build` -> `deployed` -> `on_chain_committed`; `deprecated`/`yanked`/`quarantined` suppress default search without deleting history |
17361738

17371739
### Phase 0 — No Block on v0.12
17381740

@@ -1848,19 +1850,20 @@ Any failure in this chain causes fail-closed rejection.
18481850

18491851
Namespace ownership is the core registry ACL. A namespace has owner principals;
18501852
packages have maintainer principals; publisher credentials are scoped to
1851-
actions such as `publish`, `yank`, `attest`, and `manage-maintainers`. The root
1852-
publisher principal is `joyid_ckb`, while daily operations use delegated
1853+
actions such as `publish`, `yank`, `commit`, and `manage-maintainers`. The root
1854+
publisher principal is `joyid_ckb` or `ckb_secp256k1`, while daily operations use delegated
18531855
publisher credentials that can expire and be revoked. The exact bootstrap
18541856
policy for first namespace claim (review, cooldown, reserved namespaces, or
18551857
later fee/bond hooks) is an ecosystem decision.
18561858

18571859
### Should reproducible build proofs or audit signatures be required before a package is considered production-ready?
18581860

1859-
Phase 1 requires hash matching but not build attestations or audit signatures.
1860-
Phase 2 adds optional publisher signatures and audit report hashes. Whether
1861-
audit signatures become mandatory for production readiness is an ecosystem
1862-
policy decision, not a toolchain enforcement decision. The toolchain should
1863-
support the mechanism; the policy should be set by the community.
1861+
Hash matching remains the baseline for generic artifacts. A release declaring
1862+
a reproducible build additionally requires policy-approved, P-256-signed
1863+
reproduction reports from independent trust domains before it becomes
1864+
`verified` or can acquire deployment evidence. Security audit signatures remain
1865+
policy-specific; when a release declares `security.status = audited`, the
1866+
referenced audit report must at least be present and hash-bound.
18641867

18651868
### How should yanking, supersession, and maintainer rotation work?
18661869

docs/CELLSCRIPT_REGISTRY_PHASE1.md

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ surfaces described here are checked in on the current release line.
66

77
The source-package production slice is deployed. Generic artifact,
88
reproduction, deployment, and chain-index code is implemented, but a public
9-
`on_chain_attested` claim additionally requires operators to deploy and pin the
10-
canonical mainnet Registry Type Script, its CellDep, and the attestor Lock.
11-
Until all three identities are configured, commitment construction fails
9+
`on_chain_committed` claim additionally requires operators to deploy and pin
10+
the canonical mainnet Registry Type Script, commitment custody Lock, and both
11+
code CellDeps. Until all four configuration values are present and their Cells
12+
are live with the required confirmation depth, commitment construction fails
1213
closed and scheduled chain reconciliation remains disabled.
1314

1415
The Registry indexes CKB ecosystem artifacts. A coordinate is
@@ -67,9 +68,12 @@ binary may be verified but have no deployment concept. A CKB executable may be
6768
verified and still undeployed. A previously chain-verified release may later be
6869
deprecated without rewriting its evidence.
6970

70-
`on_chain_attested` is a current-state claim, not a permanent badge. Scheduled
71+
`on_chain_committed` is a current-state claim, not a permanent badge. Scheduled
7172
maintenance returns a spent commitment to `deployed` and a stale deployment to
72-
`verified_build`, while retaining every accepted evidence record for audit.
73+
`verification_status = verified` plus `deployment_status = undeployed`
74+
(projected as `verified_build`), while retaining every accepted evidence record
75+
for audit. Disabling the Registry Script configuration also clears current
76+
commitment pointers because the service can no longer re-observe them.
7377

7478
## Artifact Identity
7579

@@ -228,17 +232,40 @@ environment and emit bounded reports:
228232

229233
```json
230234
{
231-
"schema": "cellscript-reproduction-report-v1",
235+
"schema": "cellscript-reproduction-report-v2",
232236
"builder_id": "builder-a",
237+
"trust_domain": "independent-org-a",
238+
"builder_public_key": "p256-spki:<base64-der>",
233239
"environment": "<exact signed environment>",
234240
"source_hash": "<CKB Blake2b-256>",
235241
"build_recipe_hash": "<CKB Blake2b-256>",
236242
"artifact_hash": "<CKB Blake2b-256>",
237243
"build_log_hash": "<CKB Blake2b-256>",
238-
"generated_at": "2026-08-02T00:00:00Z"
244+
"generated_at": "2026-08-02T00:00:00Z",
245+
"signature": {
246+
"algorithm": "p256-sha256",
247+
"signature": "<base64url-fixed-signature>"
248+
}
239249
}
240250
```
241251

252+
Generate each report next to the reproduced artifact and bounded build log:
253+
254+
```bash
255+
cellc artifact reproduction-report acme/vault-lock@1.0.0 \
256+
--artifact target/vault-lock \
257+
--build-log reports/builder-a.log \
258+
--builder-id builder-a \
259+
--trust-domain independent-org-a \
260+
--builder-key-id cap_<sha256-prefix> \
261+
--builder-public-key 'p256-spki:<base64url-der>' \
262+
--output reports/builder-a.json
263+
```
264+
265+
The corresponding private key must be isolated per builder. Load it from that
266+
builder's OS keychain entry, or set
267+
`CELLSCRIPT_REPRODUCER_PRIVATE_KEY_PKCS8_B64` only in its CI environment.
268+
242269
Create the operator promotion payload locally:
243270

244271
```bash
@@ -248,9 +275,14 @@ cellc artifact reproduction-evidence acme/vault-lock@1.0.0 \
248275
--output reproduced-build-promotion.json
249276
```
250277

251-
The CLI and API require two to sixteen distinct builder IDs and exact matches
252-
for the signed environment, source, recipe, and executable. The promotion also
253-
references the accepted `verified_build` evidence. A reproducible artifact
278+
The CLI verifies every report signature and requires distinct builder IDs,
279+
public keys, and trust domains. The API additionally requires each builder to
280+
match `REGISTRY_REPRODUCER_POLICY_JSON` and enforces its configured minimum
281+
trust-domain count. Both layers require exact matches for the signed environment,
282+
source, recipe, executable, and build log. The promotion also references the
283+
accepted `verified_build` evidence. Accepted evidence records the canonical
284+
policy SHA-256 and the threshold used for that decision, so later policy
285+
rotation cannot rewrite the historical trust boundary. A reproducible artifact
254286
stays `evidence_required`, and deployment admission fails, until
255287
`reproduced_build` evidence is accepted.
256288

@@ -299,9 +331,10 @@ Type/Lock hashes, and a wallet-ready mainnet transaction intent. The wallet,
299331
not the Registry or CLI, completes capacity, inputs, change, fee, witnesses,
300332
signatures, and broadcast.
301333

302-
The Registry accepts an on-chain attestation only after reading the live
303-
mainnet Cell and matching its exact data, configured attestor Lock, and
304-
configured Registry Type Script. Scheduled maintenance uses an exact Type
334+
The Registry accepts an on-chain commitment only after reading a sufficiently
335+
confirmed live mainnet Cell and matching its exact data, configured commitment
336+
Lock, and configured Registry Type Script. Readiness separately resolves and
337+
checks the Type and Lock code CellDeps. Scheduled maintenance uses an exact Type
305338
Script indexer query plus the `CSREGv1` prefix to discover commitments and
306339
reconcile their live lifecycle.
307340

@@ -313,8 +346,10 @@ application's own Lock/Type Scripts, schemas, and replacement transactions.
313346

314347
The website presents a single “Connect CKB wallet” entry. Its modal separates
315348
CCC-detected browser signers, which can connect immediately, from wallet
316-
directory entries, which open an official site and continue through the manual
317-
payload/signature path. A directory entry is never reported as connected.
349+
directory entries, which only open an external site and then require a
350+
compatible manually produced `wallet-signature.json`. A directory entry is a
351+
reference/import route, not proof that the wallet exposes a compatible message
352+
signing UI, and is never reported as connected.
318353
Network selection is not exposed because authorisation and deployment are
319354
mainnet-only.
320355

@@ -324,8 +359,10 @@ never leave the wallet. Namespace ownership, capability scope, expiry,
324359
revocation, nonce consumption, idempotency, quotas, and audit events are
325360
enforced by the API.
326361

327-
The submit form remains hidden until a wallet principal is connected or the
328-
publisher explicitly confirms that an active capability already exists.
362+
The submit form remains hidden until a direct signer is connected, a manual
363+
signature-import route is explicitly selected, or the publisher confirms that
364+
an active capability already exists. Manual payloads remain untrusted until
365+
the API verifies their principal binding and signature.
329366

330367
## Public Reads
331368

@@ -378,8 +415,9 @@ that every artifact is installable.
378415
other mirror failures are audited and retried by verification sync, so an
379416
uncommitted release or deployment is never advertised as current.
380417
- State transitions append evidence; they do not mutate hash identity.
381-
- An unconfigured or partially configured Registry Type/Lock Script set cannot
382-
produce a wallet transaction intent or current attestation.
418+
- An unconfigured, partially configured, spent, or insufficiently confirmed
419+
Registry Type/Lock Script and CellDep set cannot produce a wallet transaction
420+
intent or current commitment.
383421

384422
## Validation
385423

0 commit comments

Comments
 (0)