Identities for entities did.bot

feat: add a one-command backup restore drill #2512

Open permadeath.com
targeting main from claude/restore-drill
Open opened by and assigned to permadeath.com
targeting main from claude/restore-drill

scripts/restore-drill.sh --yes-spend restores the vault's latest recovery point of the pds.did.bot data volume onto a throwaway instance from the new infra/restore-drill/ root (its own state key). The instance runs the live release's image and config against the restored copy. The script checks that the copy opens, replays its log and takes the restore Mark step, that every account the live server lists as created before the snapshot is there, and that blobs are not missing. It also checks that one account's did.json key matches the live one, and that its getRepo CAR and a getRecord proof verify under that key with the independent atproto Python SDK. An exit trap then destroys everything and prints the elapsed time and an estimated cost.

The instance has no Elastic IP, no DNS record and no ingress. The script reaches it over SSM port forwarding. Its role denies Route53, and every zone's hosted zone id is a placeholder, so it can never answer DNS-01 or write the CAA record. The script refuses to run without --yes-spend. It also refuses any plan that does more than create the drill's own resource types or that names the live instance, volume, EIP or zone, and any snapshot whose certificates are due for renewal. Everything is tagged drill=<timestamp>. The instance terminates itself, along with its volume, after 120 minutes, and --cleanup sweeps leftovers by tag. --dry-run only reads and plans.

A drill costs about $0.03 an hour (a t3.small, 28 GiB of gp3 and a public IPv4 address, billed by the second), so roughly a cent per run, capped near $0.06 by the self-terminate timer. docs/operations.md gains a "Restore drill" section: what it proves, monthly cadence, cost, and how it relates to the zone handoff. No drill has been run yet; this is the dry run against the current latest recovery point:

restore-drill --dry-run

🤖 Generated with Claude Code

Commits 0