agent ran the migration against production because DATABASE_URL pointed at prod in its shell - how to guard against...
A guard playbook for when an agent runs a migration against production because DATABASE_URL pointed at prod: assessing what ran, and building target verification into the agent's procedure so it never happens again. Use when a migration hit the wrong database due to environment confusion. Not for migrations that failed on the correct target.
TL;DR
The agent trusted an environment variable and migrated the wrong database. First assess exactly what ran against production (read the state table, diff the schema), then make wrong-target runs structurally impossible: a wrapper that prints the resolved host and database name and requires an explicit environment flag, separate credentials per environment, and a pre-flight check that aborts on production unless explicitly confirmed.
The query
agent ran the migration against production because DATABASE_URL pointed at prod in its shell - how to guard against wrong-target runsUse this when
- An agent migrated production when it meant staging
- DATABASE_URL pointed at prod in the agent's shell
- Need a wrong-target guard for agent-driven migrations
- Post-incident: what ran against prod and how to prevent repeats
Not for
- A migration that failed on the intended database (fix the migration)
- Application code connecting to the wrong database at runtime (a config bug, not a migration guard)
- Intentional production migrations (those need a runbook, not a guard)
Steps
1. Assess exactly what ran against production
SELECT version_num FROM alembic_version;(or the equivalent state table for your tool: flywayschemahistory, prismamigrations, django_migrations). Compare against what production should be at, and diff the schema against staging.
Expected output: the list of migrations that applied to prod. If the set matches what prod was supposed to get anyway, the incident is a process failure with no schema damage. If unexpected migrations applied, treat it as a production schema incident: verify the application still works against the new schema.
2. Contain the blast radius
Rotate any credentials the agent had, check for application errors against the changed schema, and decide whether to roll forward (keep the migrations, deploy matching code) or roll back. Do not roll back reflexively: a rollback that the application is not built for is a second incident.
Expected output: a deliberate decision, recorded, with the application verified healthy in its final state.
3. Build the target-verification wrapper
Every migration the agent runs goes through a wrapper script that resolves the connection string, prints the host and database name, and requires an explicit --env flag:
#!/bin/bash
# migrate.sh: refuses to run without --env, prints the target, confirms prodThe wrapper aborts when the resolved host matches the production pattern unless a --i-understand-this-is-prod flag is also passed. Expected output: running the wrapper without flags prints the target and exits; there is no silent default that can point at prod.
4. Separate credentials per environment
Give the agent's staging and development shells credentials that physically cannot reach production: different users, different hosts, network rules. An agent cannot migrate a database it cannot connect to.
Expected output: even a confused agent holding the staging credential gets "connection refused" from prod, not a migrated prod.
5. Add the pre-flight check to the agent's procedure
Before every migration step, the agent prints the target (host, database, current version) and waits for the wrapper's confirmation gate. Bake it into the runbook so no migration command is ever typed raw.
Expected output: the runbook's migration step starts with target verification, and skipping it is impossible without editing the runbook.
Tool compatibility
Tool-agnostic: the guard pattern works for alembic, flyway, prisma, django, rails, and any CLI that reads a connection string from the environment.
Variant phrasings
agent ran migration against production wrong DATABASE_URL
Steps 1 and 2: assess what applied, then decide roll-forward vs rollback deliberately.
how to prevent migrations hitting the wrong database
Steps 3 and 4: a verifying wrapper plus credentials that cannot reach prod. Either alone is insufficient.
migration ran against prod instead of staging
Step 1: read the state table on prod first. Everything else depends on knowing exactly what applied.
Why it happens
Agents inherit shell environments wholesale, and DATABASE_URL is just a string: nothing in the migration tools verifies that the string points where the operator intended. Humans catch this with context ("this terminal is the prod one"); agents have no such context unless the procedure manufactures it. The fix is making the target explicit and verified, not hoping the variable is right.
Edge cases
- A wrapper that can be bypassed with an env var is decoration: the confirmation for prod must be a separate explicit flag, not the absence of a mistake.
- CI jobs need the same guard: a CI migration job with prod credentials and a default env is the same incident on a schedule.
- After the incident, audit every other agent runbook for raw migration commands: the same pattern usually exists in more than one place.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_LTVoDV7xsyTGJvXUy925SA