|
| 1 | +# Registry Proxy + SumDB Status |
| 2 | + |
| 3 | +## Summary |
| 4 | + |
| 5 | +This file now reflects the current implemented state. |
| 6 | + |
| 7 | +What exists today: |
| 8 | + |
| 9 | +- `registry.npmx.dev` is an npm-compatible proxy surface |
| 10 | +- `sum.npmx.dev` is a minimal transparency log for immutable tarball assertions |
| 11 | +- sumdb logs only tarball records |
| 12 | +- every logged record includes: |
| 13 | + - `keyId` |
| 14 | + - `name` |
| 15 | + - `version` |
| 16 | + - `type` |
| 17 | + - `digest` |
| 18 | + - `size` |
| 19 | + - `url` |
| 20 | + - `integrity` |
| 21 | + - `signature` |
| 22 | +- `keyId` is the actual package-signing key from npm-style `dist.signatures` |
| 23 | +- the proxy verifies the upstream package signature before ingest |
| 24 | +- sumdb verifies the same logged signature again using trusted public keys loaded at startup |
| 25 | +- sumdb does not know registry base URLs, labels, or proxy-specific routes |
| 26 | +- the proxy no longer exposes custom routes like `/registries` |
| 27 | +- package-pattern routing has been removed; the proxy fetches from the first configured source registry |
| 28 | + |
| 29 | +## Implemented Behavior |
| 30 | + |
| 31 | +### 1. Registry catalog and fetch source |
| 32 | + |
| 33 | +The checked-in registry catalog in [config/registries.ts](/Users/mohammadbagherabiyat/oss/npmx.dev/config/registries.ts) is now just an ordered list of source registries: |
| 34 | + |
| 35 | +- `label` |
| 36 | +- `registryBaseUrl` |
| 37 | + |
| 38 | +Current behavior: |
| 39 | + |
| 40 | +- source-registry keys are fetched from each registry’s `/-/npm/v1/keys` |
| 41 | +- the full catalog is used to collect trusted public keys for startup/bootstrap |
| 42 | +- the proxy uses the first configured registry as its fetch source |
| 43 | +- there are no per-package or per-scope routing rules anymore |
| 44 | + |
| 45 | +### 2. Proxy behavior |
| 46 | + |
| 47 | +Implemented in [apps/registry-proxy/src/server.ts](/Users/mohammadbagherabiyat/oss/npmx.dev/apps/registry-proxy/src/server.ts): |
| 48 | + |
| 49 | +- supports npm-compatible packument routes |
| 50 | +- supports npm-compatible tarball passthrough routes |
| 51 | +- exposes `GET /-/npm/v1/keys` |
| 52 | +- preserves source-registry tarball URLs in packuments so lockfiles do not point at the proxy |
| 53 | +- caches packuments on disk |
| 54 | +- verifies upstream `dist.signatures` before ingesting a tarball into sumdb |
| 55 | +- sends the minimal tarball record directly to sumdb |
| 56 | + |
| 57 | +Not present anymore: |
| 58 | + |
| 59 | +- `/registries` |
| 60 | +- proxy-side registry registration behavior |
| 61 | +- package-pattern routing logic |
| 62 | +- witness/envelope signing between proxy and sumdb |
| 63 | + |
| 64 | +### 3. SumDB behavior |
| 65 | + |
| 66 | +Implemented in [apps/sumdb/src/server.ts](/Users/mohammadbagherabiyat/oss/npmx.dev/apps/sumdb/src/server.ts) and [apps/sumdb/src/store.ts](/Users/mohammadbagherabiyat/oss/npmx.dev/apps/sumdb/src/store.ts): |
| 67 | + |
| 68 | +- accepts only tarball ingest records |
| 69 | +- requires `integrity` |
| 70 | +- verifies the logged `signature` against the trusted responsible public key for `keyId` |
| 71 | +- rejects unknown key IDs |
| 72 | +- stores only the minimal logged record in the Merkle tree |
| 73 | +- serves lookup, checkpoint, inclusion proof, consistency proof, and tile endpoints |
| 74 | +- signs checkpoints with its own npm-style P-256 keypair |
| 75 | + |
| 76 | +Startup model: |
| 77 | + |
| 78 | +- trusted responsible public keys are fetched outside the sumdb core |
| 79 | +- the sumdb CLI bootstraps them from the checked-in registry catalog before creating the server |
| 80 | +- the server/store itself remains registry-URL-agnostic |
| 81 | + |
| 82 | +### 4. Logged record and canonical leaf |
| 83 | + |
| 84 | +Implemented in [apps/registry-core/src/protocol.ts](/Users/mohammadbagherabiyat/oss/npmx.dev/apps/registry-core/src/protocol.ts): |
| 85 | + |
| 86 | +Logged record fields: |
| 87 | + |
| 88 | +- `keyId` |
| 89 | +- `name` |
| 90 | +- `version` |
| 91 | +- `type` |
| 92 | +- `digest` |
| 93 | +- `size` |
| 94 | +- `url` |
| 95 | +- `integrity` |
| 96 | +- `signature` |
| 97 | + |
| 98 | +The Merkle leaf is built from exactly those fields and nothing else. |
| 99 | + |
| 100 | +Why packuments are not logged: |
| 101 | + |
| 102 | +- they are mutable registry metadata, not immutable versioned artifacts |
| 103 | +- they do not have one stable package-version integrity value like tarballs do |
| 104 | +- dropping them keeps sumdb closer to a Go-sumdb-style artifact log |
| 105 | + |
| 106 | +## Public Interfaces |
| 107 | + |
| 108 | +### Ingest API |
| 109 | + |
| 110 | +`POST /ingest` currently accepts: |
| 111 | + |
| 112 | +- `keyId` |
| 113 | +- `name` |
| 114 | +- `version` |
| 115 | +- `type` |
| 116 | +- `digest` |
| 117 | +- `size` |
| 118 | +- `url` |
| 119 | +- `integrity` |
| 120 | +- `signature` |
| 121 | + |
| 122 | +Validation: |
| 123 | + |
| 124 | +- `type` must be `tarball` |
| 125 | +- `integrity` must be present |
| 126 | +- `signature` must verify for `${name}@${version}:${integrity}` |
| 127 | + |
| 128 | +### Proxy API surface |
| 129 | + |
| 130 | +Currently exposed: |
| 131 | + |
| 132 | +- `GET /<package>` |
| 133 | +- `GET /@scope/<package>` |
| 134 | +- tarball passthrough routes |
| 135 | +- `GET /-/npm/v1/keys` |
| 136 | + |
| 137 | +Currently not exposed: |
| 138 | + |
| 139 | +- `/registries` |
| 140 | +- proxy-specific registry inspection endpoints |
| 141 | + |
| 142 | +### Sumdb API surface |
| 143 | + |
| 144 | +Currently exposed: |
| 145 | + |
| 146 | +- `GET /lookup/:keyId/:packageName/:version` |
| 147 | +- `GET /latest-checkpoint` |
| 148 | +- `GET /checkpoint/:treeSize` |
| 149 | +- `GET /proof/inclusion/:leafIndex` |
| 150 | +- `GET /proof/consistency/:from/:to` |
| 151 | +- `GET /tile/...` |
| 152 | +- `POST /ingest` |
| 153 | + |
| 154 | +## Verification And Tests |
| 155 | + |
| 156 | +Verified today: |
| 157 | + |
| 158 | +- minimal-leaf and Merkle tests pass |
| 159 | +- end-to-end proxy + sumdb install flow passes with real installs |
| 160 | +- lockfile tarball URLs point to the source registry, not the proxy |
| 161 | +- proxy no longer exposes `/registries` |
| 162 | +- logged records include the upstream package signature |
| 163 | +- sumdb verifies the logged signature using startup-loaded trusted public keys |
| 164 | + |
| 165 | +Main test entrypoints: |
| 166 | + |
| 167 | +- `node --test --experimental-strip-types apps/registry-core/src/*.test.ts` |
| 168 | +- `node --test --experimental-strip-types apps/demo/src/integration.test.ts` |
| 169 | + |
| 170 | +## Assumptions |
| 171 | + |
| 172 | +- trust is per published signing key, not per registry hostname |
| 173 | +- the registry catalog is the source of truth for source-registry order and external key fetching |
| 174 | +- the first configured registry is the active fetch source for the proxy |
| 175 | +- duplicate tarball ingests are deduplicated by canonical leaf |
0 commit comments