Skip to content
VerifAIer
Home / Docs / Operations / Secrets · backup · DR
Operations · Resilience

Secrets, backup & disaster recovery

How secrets are handled, and the honest truth about backup, restore and disaster recovery: the app records the metadata, you perform the I/O.

Secret handling

Secrets are read from the environment and never leave it. The central inventory (security/secrets.py) reports presence only: never a value:

src/vailidator/security/secrets.py · providers/config.py · _build.py
SecretComponentRequired
SESSION_SECRETauthyes (prod), ephemeral if unset (sessions drop on restart)
STRIPE_SECRET_KEY / STRIPE_PUBLISHABLE_KEY / STRIPE_WEBHOOK_SECRETbillingno (only if billing is used)
GEMINI_API_KEY (GOOGLE_API_KEY fallback)providersno (only for live Gemini)
OPENAI_API_KEY / ANTHROPIC_API_KEYprovidersno (only for those live providers)
FR_SIGNING_KEYflight recorderno (dev seed otherwise)
  • Never logged or echoed: config stores boolean presence; diagnostics use mask_secret (length only); prompts/keys never enter evidence or responses.
  • Never shipped: _build.py excludes .env and all .env.* (except .env.example) from the artifact.
  • Injection: supply secrets via your platform's env / secret manager. Rotate SESSION_SECRET by redeploying with a new value (invalidates existing sessions).
  • Status: GET /api/security/status reports which secrets are configured (presence + warnings), never values.

Backup posture

Truthful scope: metadata only. BackupService tracks backup records (types database / artifacts / full; statuses pending → running → completed / failed) in the local DB. It performs no actual backup I/O: the module docstring states "No actual backup logic, metadata only." Real backups are your responsibility.
src/vailidator/reliability/backup.py
flowchart LR
  subgraph APP["VerifAIer app (metadata only)"]
    BR["BackupService, records: pending→running→completed/failed"]
    RE["RecoveryService, records: backup_* / restore_* events"]
  end
  subgraph YOU["You / infrastructure (actual I/O)"]
    SNAP["Snapshot DB_PATH file / volume"]
    STORE["Off-host storage (S3, snapshots, tape)"]
    RESTORE["Stop · replace DB file · start"]
  end
  BR -.tracks.-> SNAP
  SNAP --> STORE
  STORE --> RESTORE
  RE -.tracks.-> RESTORE
Backup/restore split, the app records metadata; you perform the real I/O. Source: reliability/backup.py + recovery.py.

Recommended real backup: the entire durable state is the SQLite file at DB_PATH:

bash

# consistent online backup of the SQLite database
sqlite3 "$DB_PATH" ".backup '/backups/vailidator-$(date +%Y%m%d%H%M).db'"

# or snapshot the docker volume (quiesce writes first for full consistency)
docker run --rm -v verifaier_data:/data -v "$PWD/backups":/out alpine \
  tar czf /out/verifaier_data-$(date +%Y%m%d).tgz -C /data .

Store copies off-host, on your own cadence (that cadence defines your RPO). If you use DATABASE_URL Postgres, back it up with your standard Postgres tooling instead.

Restore posture

Truthful scope: metadata only. RecoveryService records recovery/restore events (restore_started / restore_completed / restore_failed, etc.) but performs no automated restore: "No automated recovery logic." Restore is a manual, operator-run procedure.
src/vailidator/reliability/recovery.py

bash

# manual restore (SQLite)
docker compose stop api          # or stop the uvicorn process
cp /backups/vailidator-YYYYMMDDHHMM.db "$DB_PATH"
docker compose start api
curl -sf http://localhost:8000/health   # verify

After restore, the in-memory trust registry starts empty and rebuilds from new observations, persisted domain data (validations, receipts, CC records) comes back with the database.

Disaster recovery posture

No automated disaster recovery exists in the app. The reliability modules are a metadata foundation, not an orchestrator. DR is an infrastructure responsibility, defined by your backup cadence and hosting topology.
  • RPO is set by how often you snapshot DB_PATH (there is no continuous replication in the app).
  • RTO is: provision a host → deploy the image → restore the latest DB file → health-check. There is no automated failover.
  • Cross-region / HA: front multiple stateless API replicas with a load balancer and move shared state to Postgres (DATABASE_URL); replicate that datastore with your infrastructure's tooling.
  • Records, not actions: use BackupService/RecoveryService (and /api/reliability/status) to track your externally-run backup/restore operations for auditability.