• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperscale-stack / security / 38014756492
97%

Build:
DEFAULT BRANCH: master
Ran 10 Oct 2026 01:51AM UTC
Jobs 1
Files 94
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

10 Oct 2026 01:51AM UTC coverage: 94.317% (+2.3%) from 92.032%
38014756492

push

github

web-flow
fix(oauth2): make refresh-family revocation reliable across stores

The storage contract promised that replaying a rotated refresh token
revokes its whole family, but no store gave that revocation a
family-wide boundary. SQL ran its UPDATE and DELETE outside a shared
transaction, Redis enumerated the family before mutating it member by
member, nothing gated issuance against a completed revocation, and a
family revoked before its first token left no trace. On reuse, the SQL
and Redis stores swallowed a failed revocation, and the grants
persisted the access token before the rest of the exchange could fail.

Every store now keeps one authoritative record per token family —
active or revoked — that issuance, rotation and lookups go through: a
row locked with SELECT ... FOR UPDATE in SQL, a key written by Lua
scripts in Redis, the mutex in memory. A revocation is one idempotent
write that also works before the first issuance; lookups honour it,
and a missing record fails closed. SaveTokenPair replaces
SaveAccessToken and SaveRefreshToken, RotateRefreshToken takes the
whole replacement pair, and each exchange persists once, atomically.
The invariants are stated on oauth2.Storage and enforced by storetest
for the memory, SQL and Redis stores, races included.

A reuse whose revocation fails returns ErrRefreshTokenReused joined
with ErrTokenFamilyRevocationFailed; the refresh grant retries it on a
context detached from the request and reports a remaining failure
through grant.Config.OnError. /revoke revokes an access token's family
before deleting the token and answers 503 temporarily_unavailable (RFC
7009 §2.2.1) when a revocation may not have taken effect, reporting
each storage failure to OnError once. Also fixed: a vanished refresh
token answers invalid_grant, the empty family ID no longer revokes
every family-less token, the SQL schema runs on PostgreSQL and MySQL,
and a Redis rotation resent after a lost reply is no longer taken for
a reuse.

Breaking: t... (continued)

998 of 1029 new or added lines in 16 files covered. (96.99%)

2 existing lines in 2 files now uncovered.

4630 of 4909 relevant lines covered (94.32%)

21.0 hits per line

Uncovered Changes

Lines Coverage ∆ File
8
91.79
6.79% oauth2/store/redis/store.go
8
95.82
12.34% oauth2/storetest/conformance.go
8
97.67
oauth2/storetest/family.go
7
93.88
4.58% oauth2/store/sql/store.go

Coverage Regressions

Lines Coverage ∆ File
1
91.79
6.79% oauth2/store/redis/store.go
1
93.88
4.58% oauth2/store/sql/store.go
Jobs
ID Job ID Ran Files Coverage
1 38014756492.1 10 Oct 2026 01:51AM UTC 94
94.32
GitHub Action Run
Source Files on build 38014756492
  • Tree
  • List 94
  • Changed 17
  • Source Changed 0
  • Coverage Changed 17
Coverage ∆ File Lines Relevant Covered Missed Hits/Line
  • Back to Repo
  • 48bfaafc on github
  • Prev Build on master (#38008716408)
  • Next Build on master (#38015736430)
  • Delete
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc