feat(pnpr): derive the registry surface from declared mounts#12773
Conversation
The top-level `registry:` config key duplicated information the config
already carries and could contradict it: `mounts:` together with
`registry: {enabled: false}` declared structure and then disclaimed it.
The npm-registry surface is now served iff at least one mount is
declared under `mounts:`, minus the per-tier `--disable-registry`
override. The removed `registry:` key is rejected with migration
guidance rather than silently ignored — the parser is lenient about
unknown keys for verdaccio compat, but silently dropping a key that
used to disable a surface would fail open. The `resolver:` toggle
stays: it is the only expression of a genuinely non-derivable operator
choice and duplicates nothing.
The account endpoints (adduser/login, whoami, profile, token listing
and revocation, logout) move out of the registry surface onto
dedicated always-mounted routes: they are pnpr account management, not
package-registry functionality, and a resolver-only tier must be able
to mint the tokens its own resolver surface demands
(`pnpm login --registry https://<resolver-host>/`).
The at-least-one-surface startup check becomes a nothing-to-serve
error: no mounts (or the registry disabled by flag) and the resolver
disabled. The mount graph is still built and validated on every tier,
and a registry surface disabled by flag still skips strict upstream
credential resolution.
Closes #12767
PR Summary by Qodopnpr: derive registry surface from mounts and always mount account routes
AI Description
Diagram
High-Level Assessment
Files changed (6)
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR derives registry-surface enablement from mounts, moves account endpoints to dedicated always-on routes, removes account handling from generic dispatch, and updates related config, CLI, logging, and tests. ChangesRegistry surface derivation and account routing
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant ConfigFile
participant ConfigLoader
participant Router
participant AccountRoutes
ConfigFile->>ConfigLoader: parse mounts and resolver settings
ConfigLoader->>Router: build tier routes from derived enablement
Router->>AccountRoutes: mount whoami/login/logout/profile/token routes
AccountRoutes-->>Router: always-on account responses
Assessment against linked issues
Possibly related PRs
Suggested labels: Suggested reviewers: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
pnpr is pre-1.0 and experimental with no deployed configs to protect, so the removed `registry:` key needs no migration error - it is now just another unknown key the verdaccio-lenient parser ignores.
Code Review by Qodo
1. ensure_a_feature_is_enabled() treats --disable-registry as “nothing to serve”
|
There was a problem hiding this comment.
Pull request overview
This PR updates pnpr’s configuration and routing so the npm-registry surface is derived from declared mounts: (and can still be disabled per-tier via --disable-registry), while moving account/token endpoints onto always-mounted routes so resolver-only tiers can still mint/manage credentials.
Changes:
- Derive
registry.enabledfrommounts:presence and reject the removed top-levelregistry:config key with migration guidance. - Move account endpoints (login/adduser, whoami, profile, token list/revoke, logout) out of the registry-gated surface and mount them on every tier (including
/~<prefix>/...variants). - Update tests and bundled config comments to reflect the derived-registry model and “nothing to serve” startup validation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpr/crates/pnpr/tests/server.rs | Extends resolver-only behavior testing to include account/token flows. |
| pnpr/crates/pnpr/src/server.rs | Reworks router composition to always mount account routes and gates registry routes on derived enablement. |
| pnpr/crates/pnpr/src/main.rs | Updates CLI flag help text for --disable-registry to match derived-registry behavior. |
| pnpr/crates/pnpr/src/config/tests.rs | Updates config tests to reflect derived registry surface, removed key rejection, and “nothing to serve” checks. |
| pnpr/crates/pnpr/src/config.rs | Implements derived registry enablement, rejects removed registry: key, and updates validation/error messaging. |
| pnpr/crates/pnpr/config.yaml | Updates bundled config documentation to explain derived registry surface and always-served account endpoints. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Code review by qodo was updated up to the latest commit df63e1c |
|
Code review by qodo was updated up to the latest commit df63e1c |
…lver tiers Address PR review findings on #12773: - The adduser/login endpoint is the one body-accepting route reachable anonymously on every tier; give it a 64 KiB body cap instead of the inherited 100 MiB publish ceiling so unauthenticated callers cannot use it as a buffer-and-parse amplifier. - Exercise the /~<prefix>/ account-route twins in the resolver-only test, proving they do not depend on the absent registry segment routes. - Fix the --disable-registry help text to say the surface needs at least one mount, not merely a mounts: key.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #12773 +/- ##
==========================================
+ Coverage 85.55% 85.57% +0.01%
==========================================
Files 413 413
Lines 63908 63986 +78
==========================================
+ Hits 54679 54754 +75
- Misses 9229 9232 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pnpr/crates/pnpr/tests/auth_user_endpoints.rs (1)
164-164: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider referencing the shared body-limit constant instead of a literal.
The
65 * 1024literal isn't tied toMAX_LOGIN_BODY_BYTES(the constant enforcing this limit inserver.rs). If that constant changes, this test's magic number could silently drift out of sync with the actual limit.♻️ Suggested tie-in to the shared constant
- let body = adduser_body("alice", &"x".repeat(65 * 1024)); + let body = adduser_body("alice", &"x".repeat(MAX_LOGIN_BODY_BYTES as usize + 1024));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pnpr/crates/pnpr/tests/auth_user_endpoints.rs` at line 164, The test uses a hardcoded 65 * 1024 body size, which can drift from the real request limit; update the auth_user_endpoints test to derive the oversized payload from MAX_LOGIN_BODY_BYTES instead of a magic number. Keep the existing adduser_body call, but size the string relative to the shared constant so the test stays aligned with the server-side limit enforcement in MAX_LOGIN_BODY_BYTES.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@pnpr/crates/pnpr/tests/auth_user_endpoints.rs`:
- Line 164: The test uses a hardcoded 65 * 1024 body size, which can drift from
the real request limit; update the auth_user_endpoints test to derive the
oversized payload from MAX_LOGIN_BODY_BYTES instead of a magic number. Keep the
existing adduser_body call, but size the string relative to the shared constant
so the test stays aligned with the server-side limit enforcement in
MAX_LOGIN_BODY_BYTES.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 00de2e19-a8d2-4cb5-9510-c42a2a5cada3
📒 Files selected for processing (4)
pnpr/crates/pnpr/src/main.rspnpr/crates/pnpr/src/server.rspnpr/crates/pnpr/tests/auth_user_endpoints.rspnpr/crates/pnpr/tests/server.rs
✅ Files skipped from review due to trivial changes (1)
- pnpr/crates/pnpr/src/main.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- pnpr/crates/pnpr/tests/server.rs
- pnpr/crates/pnpr/src/server.rs
|
Code review by qodo was updated up to the latest commit ac932a0 |
npm's logout protocol (DELETE .../-/user/token/{token}) carries the raw
bearer token in the URL path, and the access TraceLayer logged the
request URI verbatim - writing a reusable credential into every log
line the logout produced. With the account endpoints now mounted on
every tier (#12773 review finding), redact everything after
the /-/user/token/ marker in the logged URI; all other URIs are logged
unchanged.
|
Code review by qodo was updated up to the latest commit 9efb050 |
|
Code review by qodo was updated up to the latest commit 9efb050 |
|
Code review by qodo was updated up to the latest commit 25ff5e1 |
1 similar comment
|
Code review by qodo was updated up to the latest commit 25ff5e1 |
…maps (#834) Documents the redesigned model from pnpm/pnpm#12773, pnpm/pnpm#12778, and pnpm/pnpm#12787: - mounts:/defaultTarget: -> registries:/defaultRegistry: - routers collapse to ordered sources: lists; a package resolves to the first listed source whose declared packages claim it - the namespace and ACL merge into per-registry packages: maps, with most-specific-key selection and namespace enforcement on every path - the registry: config toggle is gone; the npm-registry surface is served iff at least one registry is declared, minus --disable-registry - the account (login/token) endpoints are always served on every tier
Summary
Closes #12767.
Removes pnpr's top-level
registry:config key and derives the npm-registry surface from declared structure instead: the surface is served iff at least one mount is declared undermounts:, minus the per-tier--disable-registryoverride. Theresolver:toggle stays — it is the only expression of a genuinely non-derivable operator choice and duplicates nothing. A leftoverregistry:key in a config is simply ignored like any other unknown key (pnpr is pre-1.0; no compatibility shim)./~<prefix>/), so a resolver-only tier mints and manages the tokens its own resolver surface demands:pnpm login --registry https://<resolver-host>/works without a registry-serving replica sharing the auth backend. No new exposure — minting stays gated byauth.htpasswd.max_usersand existing-user passwords, and token validation already ran on every tier.Verified end-to-end: a no-mounts config starts a resolver-only tier (
registry=false resolver=true), serves/-/ping, the/-/pnprhandshake, login/whoami/token-list (also under/~corp/), and 404s packument reads; a mounts config derivesregistry=trueand--disable-registryoverrides it; a staleregistry: {enabled: false}next to mounts is ignored and derivation wins; the nothing-to-serve config fails startup with a precise error.Docs follow-up (pnpm.io): pnpr
configuration.md(drop theregistry:section),endpoints.md(move the user/token endpoint table out of the registry-gated group),cli.md(--disable-registrywording), and the install-acceleration login note.Review follow-ups (
ac932a09ab,9efb0503ba): the anonymous-reachable adduser/login route now carries its own 64 KiB body cap instead of inheriting the 100 MiB publish ceiling, and the access log redacts the raw bearer token that npm's logout protocol places in the URL path (uri=/-/user/token/<redacted>).Squash Commit Body
Checklist
pacquet/port, or the description notes what still needs porting. (pnpr-only server change; no pnpm/pacquet counterpart exists.)Written by an agent (Claude Code, claude-fable-5).
Summary by CodeRabbit
mounts;--disable-registryforces it off, with improved “nothing to serve” validation when resolver/registry can’t run.--disable-registryCLI help to clarify mounts vs resolver/registry behavior.