key helper on the challenged host; retry POSTs too
Commit

Two correctness gaps caught in review:
-
After a 3xx on /info/refs, the host that actually returns 401 is in res.Request.URL, which can differ from c.EndpointURL. Querying the helper with c.EndpointURL fetched (and on success approved) credentials under the wrong key — a miss on the next run, or a poisoned key if the retry happened to work via a follow-up redirect. New challengeURLFor() preserves the original repo path but swaps in the post-redirect scheme/host before consulting the helper.
-
Helper fallback existed only on GET /info/refs. Servers that allow anonymous discovery but require auth on the actual pack POST (e.g. Gerrit anonymous-readable + authenticated push) would fail hard. PostRPCStreamBody now does the same lookup → retry → approve/reject dance, gated on the body being io.Seeker so we can rewind it for the second attempt. PostRPC / PostRPCStream always pass bytes.NewReader, which is seekable; a caller that hands in a raw non-seekable Reader sees the 401 surface as-is (documented in the doc comment).
The retry lifecycle is now in tryHelperRetry, shared between GET and POST. Four new tests cover redirect-host keying and the POST 401-retry permutations.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com Entire-Checkpoint: 991254d4f73a