You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
registry/crates/pnpm-registry/src/auth.rs keeps both stores entirely in memory:
UserStore: username → plaintext password in a HashMap guarded by a Mutex. The module doc even calls this out: "no need for password hashing, token expiration, or on-disk persistence — everything lives in an in-memory store".
TokenStore: token → username, same shape.
Every restart wipes both. That's fine for @pnpm/registry-mock (the only consumer today) but it makes pnpr unusable as a hosted registry — operators cannot keep user accounts or tokens across process restarts, container redeploys, or crashes. This is the single biggest blocker on the parity tracking issue.
Scope
Persist users to an htpasswd file (path from config: auth.htpasswd.file, already in the verdaccio-shaped YAML).
Hash passwords on write (bcrypt — verdaccio uses bcrypt; matches the existing htpasswd toolchain).
Load the htpasswd file on startup; create it on first user registration if absent.
Persist tokens to a sibling file (or sqlite — open to either, but a flat JSONL keeps the dependency budget low). Token records: token_hash, username, created_at, last_used_at, readonly, cidr_whitelist.
Store hashes of tokens, not raw tokens, so a leaked file doesn't grant access.
Enforce auth.htpasswd.max_users (config field already documented in the bundled example).
Crash-safe writes: write to *.tmp then rename, same pattern as the tarball store.
Out of scope (separate issues)
Token revocation endpoint (DELETE /-/npm/v1/tokens/token/:tok) — straightforward once persistence lands, but it's a distinct API surface.
Token expiration / TTL.
Pluggable auth backends (LDAP, OAuth).
Acceptance
Integration test: boot pnpr → adduser → restart pnpr with the same storage dir → existing token still authenticates, existing username can log back in with the same password.
Integration test: corrupt the htpasswd file → server returns a parse diagnostic on startup, not a silent empty user list.
htpasswd file produced by pnpr can be read by htpasswd -v (cross-tool compatibility).
Written by an agent (Claude Code, claude-opus-4-7).
Part of #11973.
Problem
registry/crates/pnpm-registry/src/auth.rskeeps both stores entirely in memory:UserStore:username → plaintext passwordin aHashMapguarded by aMutex. The module doc even calls this out: "no need for password hashing, token expiration, or on-disk persistence — everything lives in an in-memory store".TokenStore:token → username, same shape.Every restart wipes both. That's fine for
@pnpm/registry-mock(the only consumer today) but it makes pnpr unusable as a hosted registry — operators cannot keep user accounts or tokens across process restarts, container redeploys, or crashes. This is the single biggest blocker on the parity tracking issue.Scope
auth.htpasswd.file, already in the verdaccio-shaped YAML).token_hash, username, created_at, last_used_at, readonly, cidr_whitelist.auth.htpasswd.max_users(config field already documented in the bundled example).auth.htpasswd.max_users: -1→ registration disabled.*.tmpthen rename, same pattern as the tarball store.Out of scope (separate issues)
DELETE /-/npm/v1/tokens/token/:tok) — straightforward once persistence lands, but it's a distinct API surface.Acceptance
htpasswd -v(cross-tool compatibility).Written by an agent (Claude Code, claude-opus-4-7).