feat(vault): background poller for canary reads + access logs - #263
Open
LiorFink00 wants to merge 1 commit into
Open
feat(vault): background poller for canary reads + access logs#263LiorFink00 wants to merge 1 commit into
LiorFink00 wants to merge 1 commit into
Conversation
Adds the background poller that closes the vault loop: on an interval it asks
each configured secrets manager's plugin to poll its audit log for reads of any
planted canary secret, records each read, raises an alert, and fans it out via
the existing alerting path.
- CanaryAccessLog table + migration (canary_access_logs_v1, chained off
vault_tables_v1) with a (canary_secret_id, event_id) uniqueness key.
- store.record_canary_access (deduped by the manager's event id) and
list_canary_access_logs.
- services/vault_poller.py: poll_once + an asyncio interval loop, started from
the app lifespan and cancelled on shutdown. THUMPER_VAULT_POLL_INTERVAL (30s).
- GET /api/vault/secrets/{csid}/access-logs to surface recorded reads.
Dedup happens BEFORE alerting (unlike the enterprise original, which alerted
then recorded): the AWS plugin polls CloudTrail with a lookback window, so the
same read re-surfaces on overlapping cycles - recording first means a single
read alerts exactly once. Covered by test_poll_once_dedupes_repeated_event.
Also drops a pre-existing unused `import json` in test_vault_api.py that was
failing lint on the base branch (#262). Ported from the enterprise implementation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DARDAxeg4NM8FKoyGMQZy
This was referenced Jul 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes the vault loop (Task 6 of the secret-manager migration, epic #255). A background poller checks each configured secrets manager's audit log for reads of planted canary secrets and alerts on them.
CanaryAccessLogtable + migrationcanary_access_logs_v1(chained offvault_tables_v1), with a(canary_secret_id, event_id)uniqueness key.store.record_canary_access(deduped by the manager's event id) +list_canary_access_logs.services/vault_poller.py—poll_once()+ an asyncio interval loop, started from the applifespanand cancelled on shutdown (try/finally). Interval viaTHUMPER_VAULT_POLL_INTERVAL(default 30s).GET /api/vault/secrets/{csid}/access-logsto surface recorded reads in the UI (Task 7).Notable deviation from the enterprise original
Dedup happens before alerting (the enterprise version alerted, then recorded). The AWS plugin polls CloudTrail with a ~20-min lookback window, so the same read re-surfaces on overlapping poll cycles; recording first means a single read alerts exactly once. Covered by
test_poll_once_dedupes_repeated_event.Also
Drops a pre-existing unused
import jsonintests/test_vault_api.pythat was failing lint on the base branch (#262).Testing
test_vault_poller.py(8): no-connections, no-secrets, detect-read, dedup, skip-unconfigured, continue-on-plugin-error, survive-poll-failure.test_vault_store.py(+4): record / dedup-by-event-id / no-event-id-not-deduped / newest-first.test_vault_api.py(+2): access-logs 404 + list.Stacked
Based on #262 → #261 → #260 → #259 → #257. Merge those first; this rebases to just the poller.
🤖 Generated with Claude Code