Repository navigation
Conversation
A firewall in front of an upstream registry denies an artifact with 403 (npm, PyPI, Maven, OCI) or 409 (NuGet) and explains why in the response body. The fetch layer reports those responses as an error, so every artifact download handler answered with its own generic 502 Bad Gateway and the reason was lost: the package manager reports a proxy fault where the upstream refused the artifact on policy grounds. Recover the status and body from the fetch error and forward them: - serveUpstreamBlock answers with the upstream status and report body, and serveArtifactError routes the plain-text download handlers through it - npm keeps its JSON error shape but passes the report through unchanged - container answers a refused blob with an OCI 403 DENIED Upstream 5xx responses and transport errors still become 502.
andrew
left a comment
There was a problem hiding this comment.
Thanks, forwarding the upstream's 403/409 instead of a generic 502 is the right behaviour. A few things before this can go in:
-
upstreamStatusparses the status and body back out of the fetcher's error string with a regex. registries is ours to change, and git-pkgs/registries#129 already addsfetch.StatusError{Code, Body}. Once that is merged and tagged, please bump registries here and replaceupstreamStatusandupstreamStatusPatternwitherrors.As(err, &statusErr).TestUpstreamStatuscan then go, or shrink to anerrors.Ascheck. -
The fetcher truncates error bodies to 1024 bytes (
maxErrBodySize), butserveUpstreamBlocklabels any body starting with{asapplication/json. A JSON report over 1KB gets served cut off mid-object as invalid JSON, which npm then fails to parse. Either only use the JSON content type whenjson.Valid(body)passes, or carry the upstreamContent-TypeonStatusErrorin registries#129 and forward that. -
In
container.goa refused blob answersDENIEDwith a fixed "blob refused by upstream policy" message and the Warn log drops the body too, so Docker clients still lose the reason the upstream gave. Put the upstream body in the OCI error message (ordetail) and include it in the log line. -
The comments repeat the commit message. Cut the doc comment on
serveUpstreamBlockto one line, drop theupstreamStatusPatterncomment along with the regex, and remove the comments added innpm.goand above the 403 check incontainer.go.
Problem
A firewall in front of an upstream registry (Sonatype Firewall Pro, for one) denies an artifact with
403for npm, PyPI, Maven and OCI, and with409for NuGet, and explains the denial in the response body.fetch.Fetcherreports those responses as an error, so every artifact download handler answered with its own generic502 Bad Gateway. The package manager then reports a proxy fault, and the reason the artifact was refused never reaches the user.Change
Recover the status code and body from the fetch error and forward them:
serveUpstreamBlockwrites the upstream status and report body (JSON body keepsapplication/json, anything else istext/plain), andserveArtifactErrorroutes the plain-text download handlers through it, so composer, conan, conda, cran, debian, julia, nuget, pypi, rpm, cargo, pub, go, gem and maven all behave the same way.403 DENIEDinstead of502 INTERNAL_ERROR.Upstream
5xxresponses and transport errors still become502.The fetch layer exposes neither the status nor the body as a typed error, so both are read back out of its message (
unexpected status %d: %s); the helper is the one place that knows this format. git-pkgs/registries#129 addsfetch.StatusError, which would let this drop the parsing.Test
internal/handler/upstream_block_test.go:TestUpstreamStatus— wrapped and unwrapped denials, transport errors and fetch sentinels.TestServeArtifactErrorForwardsPolicyBlock—403and409forwarded verbatim with the right content type; upstream5xxand transport errors still502.TestMavenHandler_ForwardsUpstreamPolicyBlock— a realfetch.Fetcheragainst an upstream that answers403with a report body; the client receives that status and body unchanged.TestNPMHandler_ForwardsUpstreamPolicyBlock— same for the npm tarball path.TestContainerHandler_BlobPolicyBlockIsDenied— a refused blob is reported as OCIDENIED.go build ./... && go vet ./... && go test ./... -count=1pass.Context
Found while running the proxy in front of Sonatype Firewall Pro, where a blocked package was indistinguishable from a broken proxy. The change is generic: any upstream that refuses an artifact with
403/409and a body benefits.Companion change: git-pkgs/registries#129 — a 4xx answer no longer counts against the per-host circuit breaker, so a run of policy denials cannot open it for every registry that host serves.