gabriel / musehub public
fix BREAKING fix/auth-challenge-db #1 / 1
gabriel · 170 days ago · Apr 10, 2026 · Diff

fix: store auth challenges in Postgres for blue-green deploy resilience

Replace process-local in-memory dict (_pending_challenges) with a musehub_auth_challenges Postgres table. Any server instance can now verify a challenge regardless of which slot issued it.

Changes: - Add MusehubAuthChallenge ORM model (musehub_auth_models.py) - Alembic migration 0039 creates musehub_auth_challenges table - create_challenge() is now async and takes a session param - verify_and_authenticate() queries + deletes the challenge row atomically - Route handler awaits create_challenge(session, ...) - 6 new regression tests covering persistence, single-use, replay prevention, expiry, and blue-green session isolation - type-contracts.md updated

sha256:23300e4e38936ac3fdea561219b3aca3f34c6d87b897b03d44a0151341e5a3ec sha
+36 ~11 −5 symbols
sha256:4baaaeca24fc2f30bbaa8300c275e334cb4e8dc512a0b4557c220dbcaa73387f snapshot
+36
symbols added
~11
symbols modified
−5
symbols removed
0
dead code introduced
Semantic Changes 52 symbols
+ branch_labels variable variable branch_labels L17–17
+ depends_on variable variable depends_on L18–18
+ down_revision variable variable down_revision L16–16
+ downgrade function function downgrade L38–40
+ op import import op L12–12
+ sa import import sa L13–13
+ revision variable variable revision L15–15
+ upgrade function function upgrade L21–35
+ _b64url function function _b64url L35–36
+ _fp function function _fp L39–40
+ _kp function function _kp L43–47
+ _sign function function _sign L50–51
+ AsyncClient import import AsyncClient L23–23
+ AsyncSession import import AsyncSession L25–25
+ Ed25519PrivateKey import import Ed25519PrivateKey L22–22
+ MusehubAuthChallenge import import MusehubAuthChallenge L27–27
+ annotations import import annotations L14–14
+ base64 import import base64 L16–16
+ datetime import import datetime L19–19
+ hashlib import import hashlib L17–17
+ pytest import import pytest L21–21
+ select import import select L24–24
+ time import import time L18–18 ← moved from musehub/services/musehub_auth.py
+ timedelta import import timedelta L19–19
+ timezone import import timezone L19–19
+ test_blue_green_resilience function async_function test_blue_green_resilience L210–249
+ test_challenge_consumed_on_successful_verify function async_function test_challenge_consumed_on_successful_verify L87–123
+ test_challenge_replay_rejected function async_function test_challenge_replay_rejected L127–156
+ test_challenge_stored_in_db function async_function test_challenge_stored_in_db L60–83
+ test_expired_challenge_rejected function async_function test_expired_challenge_rejected L179–206
+ test_unknown_challenge_token_rejected function async_function test_unknown_challenge_token_rejected L160–175
~ docs/reference/type-contracts.md .md 1 symbol added, 3 symbols modified
+ py` section MusehubAuthChallenge — `musehub/db/musehub_auth_models.py` L3874–3890
~ musehub/api/routes/api/auth.py .py 1 symbol modified
~ musehub/db/musehub_auth_models.py .py 1 symbol added
+ MusehubAuthChallenge class class MusehubAuthChallenge L95–128
~ musehub/services/musehub_auth.py .py 3 symbols added, 5 symbols removed, 7 symbols modified
− _ChallengeEntry variable variable _ChallengeEntry L75–75
− _ChallengeMap variable variable _ChallengeMap L76–76
− _pending_challenges variable variable _pending_challenges L80–80
− _purge_expired_challenges function function _purge_expired_challenges L88–93
− time import import time L45–45 → moved to tests/test_musehub_auth_challenge_db.py
+ MusehubAuthChallenge import import MusehubAuthChallenge L61–61
+ delete import import delete L47–47
+ timedelta import import timedelta L45–45
~ select
~ update
← Older Oldest on fix/auth-challenge-db
All commits
Newer → Latest on fix/auth-challenge-db

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:23300e4e38936ac3fdea561219b3aca3f34c6d87b897b03d44a0151341e5a3ec --body "your comment"