fix(config): normalize registry URL trailing slash in nerfDart to prevent scope key mismatch#9555
fix(config): normalize registry URL trailing slash in nerfDart to prevent scope key mismatch#9555heunghingwan wants to merge 2 commits into
Conversation
…vent scope key mismatch
owlstronaut
left a comment
There was a problem hiding this comment.
Nice work, this fixes the real scope-collapse bug and I confirmed the path now survives nerfing. Two things give me pause though: since getCredentialsByURI and logout's getAuth only check the single normalized key without backtracking, a registry configured without a trailing slash now breaks npm logout (it can't find //host/npm/, throws ENEEDAUTH, and leaves the token in .npmrc), and existing users whose tokens are stored at the old //host/:_authToken will start getting ENEEDAUTH on publish/whoami even though the wire-level auth still works. I think normalizing the slash in logout.js before getAuth, and giving getCredentialsByURI the same backtracking that npm-registry-fetch already does, would close both gaps. Could you also add a test or two for the new nerfDartURI behavior?
…alize logout registry - Add #findAuthNerf to getCredentialsByURI, walking up the nerf dart path like npm-registry-fetch's regFromURI so legacy credentials stored at a less specific key (e.g. //host/ for a registry configured as https://host/npm) are still resolved after trailing-slash normalization. - Normalize the trailing slash on the registry URL in logout before getAuth, npmFetch, and clearCredentialsByURI so logout finds the token at //host/npm/ instead of throwing ENEEDAUTH and leaving it in .npmrc. - Export nerfDartURI from @npmcli/config and add tests for its trailing-slash behavior, getCredentialsByURI backtracking, and the logout no-slash case.
|
Thanks for the thorough review @owlstronaut — both gaps were real, and reproducing the logout case confirmed the token-stranding behavior you described. Pushed an update (357ae2c) addressing all three points: 1. 2. 3. Tests for All existing config snapshots are unchanged, and |
Problem
nerfDart()in@npmcli/configusesnew URL('.', url)to compute a scope key (e.g.//host/path/) for credential lookup. URL resolution treats a path without a trailing slash as a file, so the last segment is discarded:nerfDartoutputhttps://host/npm///host/npm/https://host/npm//host/(segment lost)getCredentialsByURIonly checks this single computed key with no backtracking. This means a registry URL with a path component (e.g.https://host/npm) produces the scope key//host/, which collapses auth to the entire host and can collide with other registries on the same host at different paths.Meanwhile,
npm-registry-fetch(the HTTP layer) uses its own path-backtracking logic and handles this correctly.Fix
Introduce
nerfDartURI()— a wrapper aroundnerfDart()that ensures the URL pathname always ends with/before computing the scope key. Since all callers (getCredentialsByURI,setCredentialsByURI,clearCredentialsByURI, and the auth validation invalidate) receive registry base URLs (not package/API URLs), this normalization is safe.Updated all 4
nerfDart()call sites inworkspaces/config/lib/index.jsto usenerfDartURI().Before vs After
Both
https://host/npm/andhttps://host/npmnow produce the same key//host/npm/.Impact
.npmrcfiles with auth stored at an incorrect collapsed scope (//host/:_authTokeninstead of//host/path/:_authToken) will neednpm loginto regenerate the key at the correct scope.