internal/handlers has exactly four test functions, all covering ETag/HEAD behavior on HandleImage: TestHandleImage_HEAD_ReturnsHeadersOnly, ..._IfNoneMatch_Returns304, ..._IfNoneMatch_DifferentETag, ..._ETagHeader.
This is the thinnest-tested package in the repo and the one with the most user-visible surface. Untested:
401 on a missing or invalid signature for a non-allowlisted host. This is the product's core security boundary — the thing standing between pixa and being an open proxy — and no Go test exercises it.
400 on an unparseable path or bad fit mode
403 on ErrSSRFBlocked
502 on ErrUpstreamError
410 on an expired signature
HandleRobotsTxt, HandleHealthCheck
Status-code mapping is exactly the kind of logic that silently regresses during refactors, and #39 has more package extraction planned.
Definition of done
Table-driven tests over the error paths above, asserting status code and the JSON error body shape, using the mock fetcher (internal/httpfetcher.MockFetcher) so no network is required.
Explicit positive and negative signature cases: valid signature succeeds; tampered signature, absent signature, and expired signature each produce their documented status. Exercise the exact-match guarantee from #40 at the handler layer, not just in internal/signature.
Allowlisted host without a signature succeeds (the documented bypass) — pinning that the bypass is scoped to allowlisted hosts only.
New tests only; no existing test is modified (no owner approval needed for new tests).
t.Parallel() on each test, matching the convention the canonical lint config enforces.
make check green.
Related
Filed separately: coverage for /v1/e/ and the auth flows, which are also entirely untested in Go.
Verified against `main` at `61f42e6`.
`internal/handlers` has exactly four test functions, all covering ETag/HEAD behavior on `HandleImage`: `TestHandleImage_HEAD_ReturnsHeadersOnly`, `..._IfNoneMatch_Returns304`, `..._IfNoneMatch_DifferentETag`, `..._ETagHeader`.
This is the thinnest-tested package in the repo and the one with the most user-visible surface. Untested:
- **401 on a missing or invalid signature for a non-allowlisted host.** This is the product's core security boundary — the thing standing between pixa and being an open proxy — and no Go test exercises it.
- 400 on an unparseable path or bad fit mode
- 403 on `ErrSSRFBlocked`
- 502 on `ErrUpstreamError`
- 410 on an expired signature
- `HandleRobotsTxt`, `HandleHealthCheck`
Status-code mapping is exactly the kind of logic that silently regresses during refactors, and #39 has more package extraction planned.
## Definition of done
1. Table-driven tests over the error paths above, asserting status code **and** the JSON error body shape, using the mock fetcher (`internal/httpfetcher.MockFetcher`) so no network is required.
2. Explicit positive and negative signature cases: valid signature succeeds; tampered signature, absent signature, and expired signature each produce their documented status. Exercise the exact-match guarantee from #40 at the handler layer, not just in `internal/signature`.
3. Allowlisted host without a signature succeeds (the documented bypass) — pinning that the bypass is scoped to allowlisted hosts only.
4. New tests only; no existing test is modified (no owner approval needed for new tests).
5. `t.Parallel()` on each test, matching the convention the canonical lint config enforces.
6. `make check` green.
## Related
Filed separately: coverage for `/v1/e/` and the auth flows, which are also entirely untested in Go.
clawbot
added this to the 1.0.0 milestone 2026-08-09 03:48:01 +02:00
Plan, checked against next at 6830bdc. Since this issue was filed, internal/handlers gained tests for the 400 cases (q, fit, exp, query string), the CSRF and login-limit paths, max-age and the busy 503. Still untested at the handler layer, and what this unit adds (new tests only, t.Parallel(), the mock fetcher, no network):
One table-driven test of /v1/image/ error answers, checking the status and the JSON error body: missing, tampered and expired signature on a host that is not allowlisted (401, 401, and whatever the handler answers for an expired one, as README.md documents it), an unparseable path (400), a blocked upstream address (403), an upstream error (502).
A valid signature succeeds; an allowlisted host without a signature succeeds, and the same request for a host that is not allowlisted is refused, pinning that the bypass is scoped to allowlisted hosts. The exact-match check of #40 is exercised through the handler: a signature that differs only in padding or case is refused.
HandleRobotsTxt and HandleHealthCheck answer 200 with their documented body.
Where a status the handler gives differs from what README.md says, the test pins the code's answer and the PR names the difference; fixing either belongs to its own issue.
Model: opus-5-5
Plan, checked against `next` at `6830bdc`. Since this issue was filed, `internal/handlers` gained tests for the 400 cases (`q`, `fit`, `exp`, query string), the CSRF and login-limit paths, `max-age` and the busy 503. Still untested at the handler layer, and what this unit adds (new tests only, `t.Parallel()`, the mock fetcher, no network):
- One table-driven test of `/v1/image/` error answers, checking the status and the JSON error body: missing, tampered and expired signature on a host that is not allowlisted (401, 401, and whatever the handler answers for an expired one, as `README.md` documents it), an unparseable path (400), a blocked upstream address (403), an upstream error (502).
- A valid signature succeeds; an allowlisted host without a signature succeeds, and the same request for a host that is not allowlisted is refused, pinning that the bypass is scoped to allowlisted hosts. The exact-match check of https://git.eeqj.de/sneak/pixa/issues/40 is exercised through the handler: a signature that differs only in padding or case is refused.
- `HandleRobotsTxt` and `HandleHealthCheck` answer 200 with their documented body.
- Where a status the handler gives differs from what `README.md` says, the test pins the code's answer and the PR names the difference; fixing either belongs to its own issue.
Model: opus-5-5
Tests are in #177, per the plan above. One difference from the issue body: an expired signature is answered 401, not 410, and README.md names no status for it; the test pins 401.
Model: opus-5-5
Tests are in https://git.eeqj.de/sneak/pixa/pulls/177, per the plan above. One difference from the issue body: an expired signature is answered 401, not 410, and `README.md` names no status for it; the test pins 401.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Verified against
mainat61f42e6.internal/handlershas exactly four test functions, all covering ETag/HEAD behavior onHandleImage:TestHandleImage_HEAD_ReturnsHeadersOnly,..._IfNoneMatch_Returns304,..._IfNoneMatch_DifferentETag,..._ETagHeader.This is the thinnest-tested package in the repo and the one with the most user-visible surface. Untested:
ErrSSRFBlockedErrUpstreamErrorHandleRobotsTxt,HandleHealthCheckStatus-code mapping is exactly the kind of logic that silently regresses during refactors, and #39 has more package extraction planned.
Definition of done
internal/httpfetcher.MockFetcher) so no network is required.internal/signature.t.Parallel()on each test, matching the convention the canonical lint config enforces.make checkgreen.Related
Filed separately: coverage for
/v1/e/and the auth flows, which are also entirely untested in Go.Plan, checked against
nextat6830bdc. Since this issue was filed,internal/handlersgained tests for the 400 cases (q,fit,exp, query string), the CSRF and login-limit paths,max-ageand the busy 503. Still untested at the handler layer, and what this unit adds (new tests only,t.Parallel(), the mock fetcher, no network):/v1/image/error answers, checking the status and the JSON error body: missing, tampered and expired signature on a host that is not allowlisted (401, 401, and whatever the handler answers for an expired one, asREADME.mddocuments it), an unparseable path (400), a blocked upstream address (403), an upstream error (502).HandleRobotsTxtandHandleHealthCheckanswer 200 with their documented body.README.mdsays, the test pins the code's answer and the PR names the difference; fixing either belongs to its own issue.Model: opus-5-5
Tests are in #177, per the plan above. One difference from the issue body: an expired signature is answered 401, not 410, and
README.mdnames no status for it; the test pins 401.Model: opus-5-5
clawbot referenced this issue2026-10-04 14:12:15 +02:00