Re-mint watchpr's Gitea token when it expires #10
Reference in New Issue
Block a user
Delete Branch "benvin/watchpr-auth-expiry"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Vault-minted Gitea tokens last ~1h, far less than a watch, so every poll past expiry 401'd into a warning while watchpr looked healthy and saw nothing.
Reviewed diff +
go test -race ./...(all pass). Core correctness checks out:do/attemptsplit (internal/agent/gitea.go:394-436): body is marshalled once to[]byteindo, a freshbytes.NewReaderis built perattemptcall, so the replay is a genuine second request, not a re-read of a drained reader. Confirmed byTestRemintReplaysRequestBody.docallsattempta maximum of twice; aRefresh()error returns immediately wrapped as an auth error, never retried again.TestAuthFailureSurvivesRemint/TestRemintErrorIsReportedAsAuthFailureback this up.Watchnon-zero; 5xx/network errors keep the old warn-and-continue path (TestServerErrorDoesNotRemint,TestWatchContinuesPastServerError).attemptomitsAuthorizationentirely whenToken==""(gitea.go:430-433);doonly callsRefreshwhenIsAuthError(err), so a 200 never mints (TestAnonymousPollingNeverMints). Startup failure to mint is now a warning, not fatal, only inwatchpr'sclientFor—agentpr'sclient()(cmd/agentpr/main.go:47-53) is untouched and still fails fast, andRefreshGiteaTokenre-mints from the same env-derived role/creds path, so no command can end up acting as a different identity than before.Two non-blocking design notes, since you asked me to reason about thundering-herd behaviour explicitly:
RefreshGiteaToken(internal/agent/token.go:109-115) has no single-flight/coalescing: it unconditionally re-mints on every call. The global mutex serializes concurrent callers (no data race, no lost update) but does not dedupe them — N concurrent 401s on a shared client would still cost N sequential Vault mints, not 1. Not reachable today:Watchdrives one*GiteaClientfrom a single goroutine, and everycmd/*entrypoint does the same, so this is latent rather than a live bug. Worth a comment or a follow-up if a client is ever shared across goroutines.GiteaClient.Tokenis mutated indo()(gitea.go:415) with no synchronization on the client itself — fine under the current one-goroutine-per-client usage, would race under concurrent use of the same client instance.Minor scope note: the PR bundles two related-but-distinct concerns — (1) mid-watch token expiry (remint/replay/abort) and (2) anonymous polling when no token can be minted at all (a startup-time fallback, previously fatal). Both are small and well tested, so I'm not requesting a split, just flagging it since (2) trades a fast-fail on Vault misconfiguration for silent-if-nobody-reads-stderr degraded operation on public repos. That tradeoff is intentional and documented (AGENTS.md, PR body), just worth being deliberate about.
PR body is within the size/format convention (6 lines, 412 chars, why + present-tense bullets).