Files
ServerKit/backend/app/models
Juan DenisandClaude Opus 4.8 749152c09e fix(agent): fail-closed auth + heartbeat reaper reconnect race
Two defects in the agent control plane found during the deep-dive review.

1. verify_agent_auth() failed OPEN on a missing secret (critical). The HMAC
   check was wrapped in `if api_secret:`, so when get_api_secret() returned
   None (NULL ciphertext, or a decryption error it swallows) the signature
   block was skipped and execution fell through to "authenticated" — reducing
   agent auth to agent_id + api_key_prefix, both non-secret observable values.
   Now mandatory: no decryptable secret => log + track_auth_attempt(False) =>
   return None. Also added Server.get_pending_api_secret() and select the
   secret matching whichever prefix matched, so signatures actually verify
   during a key-rotation window instead of hitting the old bypass.

2. Heartbeat reaper evicted freshly-reconnected agents (TOCTOU race).
   _check_heartbeats snapshotted dead server_ids under the lock then released
   it; _handle_agent_timeout popped unconditionally. An agent that reconnected
   in that window (new ConnectedAgent, new socket_id) got clobbered and flipped
   offline right after reconnecting. The snapshot now carries socket_id, and
   _handle_agent_timeout re-validates under the lock (same socket AND still
   stale) before evicting. Extracted HEARTBEAT_TIMEOUT so the scan and the
   re-check can't drift; added the missing rollback on error.

Adds tests/test_agent_registry_security.py (5 tests). Full suite: 80 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 14:38:30 -04:00
..