Loading
Draft: fix(auth): emit the S01 error envelope on PyPI 401 responses
What
Unauthenticated requests on /<slug>/pypi/... returned a bare 401 with an
empty body. That contradicts S34's Error Cases
("Auth missing on a non-public endpoint | 401, code: "unauthorized"") and
fails the external conformance catalog's pypi.negative.unauthenticated row
("401 with a machine-readable error body"). twine and Poetry surface the
response body text to the user, so the empty body also reads as an opaque
failure in real clients.
How
bodyWriternow takes the request and commits the full 401 response (status line + body);noBodywrites the bare status,ociBodyis unchanged in behavior.- New
pypiBodyemits the S01 envelope viatransport.WriteError—code: "unauthorized",message: "authentication required", and the correlation-derivedrequest_id— matching what the middleware already does for its 404 path. - The npm/maven/api-v1/v2-auth-token rows keep their spec-pinned empty body: their specs have not been amended, and the equivalent ruling for those formats belongs to their owners.
- S08's Error Cases table now records the PyPI body shape, deferring to S34 (which already mandated it — the implementation had followed S08's older wording).
Tests
- Adds the PyPI row to the middleware negative-path table tests (it was
the only dispatch row with no middleware coverage) and asserts the exact
envelope wire shape via
JSONEq. go test -race ./internal/auth/green; full build + golangci-lint clean.
e2e scenario impact
Confirms e2e.pypi.auth.invalid-credentials ("upload fails with a clear
401") — the envelope is what makes the 401 "clear" in twine's output. No
new scenario: the behavior is covered by the external conformance
catalog's pypi.negative.unauthenticated row.
Related to #365