feat(auth): add non-blocking async challenge interface and...
Your AI's guard dog to stop it from going rogue.
Brought to you by:
doberman
Originally created by: Maqbool61
Closes [#144]
A non-blocking challenge path alongside the existing synchronous one. The caller
issues a challenge and immediately receives a ChallengeHandle token — no blocking,
no prompt shown. Later, when the human has decided via whatever out-of-band channel
the operator has wired, resolve_challenge() settles the handle and returns a normal
AuthResult.
src/doberman/auth/async_challenge.py — new module: ChallengeHandle, AsyncChallengeBackendInMemoryAsyncBackend, issue_challenge(), resolve_challenge(),active_async_backend() registry lookupsrc/doberman/engine/registry.py — added ASYNC_CHALLENGE_BACKEND_GROUP constanttests/unit/test_async_challenge.py — 26 testsAuthResult_settle() is write-once under lock; action-ID mismatch raises ValueErrorAuthResult structure unchangeddoberman.auth never imports doberman.proxy/hosthooks/dash/turngate; both contracts KEPTruff check ✓ · ruff format --check ✓ · lint-imports ✓ (2 contracts kept) · pytest tests/unit/ ✓ (26 new, full suite green)
Ticket changed by: fu351
Originally posted by: fu351
Merged. This is a model interface-only slice: nothing in the live decision path references the new module,
resolve()reuses the same rate-limitedtotp.verify()as the sync path instead of reimplementing it weaker, every terminal state denies (expiry, wait-timeout, missing or bad code, action-id mismatch), andtest_concurrent_resolvers_only_one_winsactually races threads at a Barrier rather than asserting idempotency on faith.One non-blocking nit for the future wiring PR: two concurrent resolvers can both clear the "not yet resolved" check, so a losing bad-code resolve still burns a TOTP lockout attempt. Stricter rather than weaker, so it can wait.
You picked a hard first issue here and landed it cleanly. If you want another with real depth: [#245] (OpenTelemetry
AuditSink, level-4) is a subsystem behind an existing interface, much like this one. We are also on Discord if you want faster feedback loops: https://discord.gg/Sfy5XGNqtyRelated
Tickets:
#245