Repository navigation
Conversation
npm metadata served through the rewrite cache lost the stale Warning header, and every upstream error fell back to the cached copy, hiding a 404 for an unpublished package and a 401/403 for broken credentials. serveRewrittenMetadata now sets Warning 110 when the document came from the stale fallback. A 401/403 is an upstreamStatusError, and fetchMetadataFromUpstream returns 404/401/403 to the caller instead of falling back; transport errors and retryable statuses (429, 5xx) still serve the cached copy. The npm metadata handler relays a default-registry 401/403 as that status. Routed packages keep answering 502, since a route's credentials are the proxy's concern and a relayed 401 would send npm off authenticating to the proxy. Fixes git-pkgs#499 Signed-off-by: Mohamed Labiadh <47183211+medlabib@users.noreply.github.com>
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
simonchrz
left a comment
There was a problem hiding this comment.
Thanks for picking up #499. The stale Warning header for rewritten npm metadata looks good.
The no-fallback change affects every ecosystem, though, not just npm. fetchMetadataFromUpstream also serves Composer, PyPI, Alpine, Debian and generic metadata. On main, cached metadata is served on an upstream 404/401/403. With this PR those requests fail. That contradicts the docs (generic upstreams are served stale when the upstream "refuses", and GitHub rate limits are 403s) and the 404 fallback described in #486.
Could you split it? I'd approve the Warning header part as is. The 404/401/403 behaviour either goes to an issue, or becomes opt-in for the npm handler only.
Nit: writeNPMetadataError is missing an "M".
andrew
left a comment
There was a problem hiding this comment.
I independently confirmed the shared-fallback regression described in #503 (review). Through the generic HTTP handler with an expired cached document, upstream 404/401/403 produce 404/502/502 on this head. The same test on main returns the cached body with status 200 and Warning 110 for all three. Please keep the stale-warning fix and scope the new fallback policy to npm, or split that policy into a separate change, preserving other ecosystems' documented fallback behavior. Add a regression test through a non-npm handler.
Fixes #499.
With
cache_metadataon, npm metadata that fell back to the cache was served through the rewrite path (cachedRewrite→serveRewrittenMetadata) as a plain200, without theWarning: 110 - "Response is Stale"header thatProxyCachedsets on the same fallback. And every upstream error triggered that fallback, including a 404 for a package the registry has unpublished and a 401/403 for credentials that stopped working, so neither answer reached the client.What changed:
rewrittenMetadatacarriesstale, set from the fetch result inhandlePackageMetadata, andserveRewrittenMetadatasetsWarning: 110 - "Response is Stale"when it is set. A 304 keeps the headers it has today.upstreamStatusError, andfetchMetadataFromUpstreamreturns 404/401/403 to the caller instead of falling back to the cached copy. Transport failures and retryable statuses (429, 5xx) still serve the cached copy with the warning, which is what the docs promise for outages and rate-limit holds.errorbody, so a broken upstream credential fails loudly. Routed packages keep the existing 502: a route's credentials are the proxy's concern, and relaying its 401 would send npm off to authenticate against the proxy.TestNPMRoutedMetadataDoesNotFallBackstill passes.Tests, in the new
internal/handler/npm_metadata_stale_test.go:Warningheader with the rewrite cache on and off, and returns the cached body (this fails onmain: no header, and 404/401/403 are served as a stale 200);Warning;errorbody and not the cached packument;Warning, guarding the rate-limit/hold fallback.Not included: a maximum stale age for the fallback, which the issue mentions as optional.
AI disclosure: prepared with AI assistance (Hermes agent); the change was verified with the test suite and lint run above.