Repository navigation
Fix npm search routing and abbreviated packuments under cooldown - #567
Merged
Merged
Conversation
`npm search` requests /-/v1/search?text=... . The path has no "/-/" after the leading slash is trimmed, so it fell through to the package metadata handler: upstream got /-/v1%2Fsearch without the query string, and the answer was cached under "-/v1/search", so every later search was served the first one's results. Search and /-/ping (used by `npm ping`, which lost its query string the same way) are now relayed to upstream uncached with their query strings, like the signing-keys endpoint. Packuments share one metadata cache row whatever format they were fetched in. Without cooldown the proxy asks for the abbreviated format, which has no "time" map. After cooldown was turned on, a still-fresh abbreviated packument kept being served from cache, and used as the stale copy when upstream failed, so cooldown filtered nothing and the tarball check let recent versions through. When full metadata is required (cooldown or npm_full_metadata on), packument lookups now pass a validator that rejects an abbreviated document (top-level "modified", no "time"), so it counts as a cache miss, is refetched in full and is never used as a stale fallback. Behaviour without cooldown is unchanged. fetchMetadataDocument takes the validate callback that fetchOrCacheMetadata already has; other callers pass nil.
andrew
approved these changes
Oct 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two npm bugs.
npm searchreturned other searches' results./-/v1/search?text=...has no/-/once the leading slash is trimmed, so it fell through to the package metadata handler. Upstream got/-/v1%2Fsearchwithout the query string, and the answer was cached under-/v1/search, so later searches were served the first one's results./-/pinglost its query string the same way. Both are now relayed to upstream uncached with their query strings, like the signing-keys endpoint./-/whoamiand the user endpoints are left alone: the proxy sends its own upstream credentials, so relaying them would report the proxy's identity.Cooldown filtered nothing when an abbreviated packument was still cached. Packuments share one metadata cache row whatever format they were fetched in. Without cooldown the proxy asks for the abbreviated format, which has no
timemap. After cooldown was turned on, a still-fresh abbreviated packument kept being served from the cache. It was also used as the stale copy when upstream failed. In both cases cooldown filtered nothing and the tarball check let recent versions through.When full metadata is required (cooldown or
npm_full_metadata), packument lookups now pass a validator that rejects an abbreviated document. It recognises one by a top-levelmodifiedand notime. The rejected document counts as a cache miss, is fetched again in full, and is never used as a stale fallback. A full document withouttime, as some registries serve, still passes.fetchMetadataDocumenttakes thevalidatecallback thatfetchOrCacheMetadataalready has; the other callers pass nil.Tests:
TestNPMSearchRelaysQueryUncachedandTestNPMPingRelaysUpstream.TestNPMCooldownRefetchesCachedAbbreviatedPackumentandTestNPMCooldownTarballRefetchesCachedAbbreviatedPackument.TestNPMCooldownSkipsAbbreviatedStaleFallback.All five fail on main.