Destructive Diff Gate: Catch DROP TABLE, Risky Migrations, rm -rf & Force Pushes Before They Ship
Tests run against a fresh database, so they rarely notice a change that deletes data. A coding agent (or a tired person) can slip a DROP TABLE, a DELETE FROM with no WHERE, a migration that removes a column, rm -rf $DIR/, git push --force or prisma migrate reset into a change that looks routine. Destructive Diff Gate scans this diff's destructive changes before they're committed or merged.
What it checks: 30 rules over the lines the diff adds
• SQL, in .sql files and SQL strings in code:
• DROP TABLE / DATABASE / SCHEMA, DROP COLUMN, TRUNCATE
• DELETE and UPDATE with no WHERE (a WHERE on the next line counts)
• Column type changes and renames (shown as MEDIUM)
• Migrations: Rails, Django, Alembic, Knex, Laravel, Sequelize, Prisma and Supabase/raw SQL.
• Dropped tables and columns, renames, type changes
• Code inside down / downgrade / -- migrate:down rollback parts is skipped, so a normal "create table" migration doesn't trip it
• A migration file deleted (HIGH) or edited after the fact (MEDIUM), and a model removed from schema.prisma
• ORM calls that delete every row, such as deleteMany({}), delete_all and objects.all().delete()
• Commands in shell scripts, CI YAML, Makefiles, Dockerfiles and package.json scripts:
• rm -rf on /, ~, $HOME, *, an unquoted $VAR or $VAR/... (${VAR:?} is recognised as safe)
• git push --force, git reset --hard, git clean -fdx
• terraform destroy, kubectl delete namespace/pvc/--all, docker system prune -a, docker compose down -v
• prisma migrate reset, --accept-data-loss, supabase db reset, rails db:drop, manage.py flush, FLUSHALL
• Env vars removed from .env.example-style files, or from env: / environment: blocks in GitHub Actions, GitLab CI, docker-compose or Kubernetes YAML (MEDIUM).
Every finding shows the rule, file:line, the line itself and why it matters. Output as text, JSON or GitHub annotations.
Gates, one command each. Existing hooks are never overwritten.
• A git pre-commit hook that blocks a commit with a HIGH finding. It works with any agent or editor (Claude Code, Codex, Cursor and others) because it sits on git.
• A GitHub Actions pull-request check that compares the branch with its base. This is the real enforcement, since --no-verify skips local hooks.
When a destructive change is intended, add ddgate: allow <rule> <reason> on the line, or an entry in .ddgate.json. A reason is required. Allowed findings still show up, with the reason, and any change to the allow-list file is reported.
Free alternatives, and when they're enough
• AgentLint (https://github.com/mauhpr/agentlint) is free and checks the risky file changes and shell commands an agent proposes during a session. If you want guardrails inside the agent session, start there.
• strong_migrations (https://github.com/ankane/strong_migrations) is free. If your app is Rails-only, it checks migrations in more depth than this kit.
• Destructive Diff Gate is for the git diff itself, at commit and PR time, whoever wrote it, across mixed stacks plus scripts and CI files.
How it was checked
• 48 unit tests pass on Python 3.8 and 3.13 (Linux). They use real throwaway git repos and cover every rule, the allow-list and cases that must not be flagged. One test makes a real git commit that is blocked and then allowed.
• The scan was run on the last 30 commits of three open-source projects (Rails, Django and shell). It raised 0 HIGH and 5 MEDIUM findings. Those histories had almost no destructive changes, so this measures noise, not how much it catches.
Who it's for: developers and indie hackers who let Claude Code, Codex, Cursor or another agent write migrations, scripts and CI config, and anyone who merges agent branches into a project with a real database.
Compatibility:
• Python 3.8+, standard library only, plus git. One file. No installs, no account, nothing uploaded.
• Plain files you can read and edit. The installers copy the tool into your repo (.ddgate/bin/), so CI and teammates have it too.
Honest limits
• It's a pattern check on this diff, not a security audit. It doesn't look for secrets, injection or vulnerable dependencies.
• It uses regular expressions over diff lines, not a parser.
• It can miss destructive changes: SQL built at run time, a dangerous helper defined elsewhere, frameworks it has no pattern for.
• It can flag harmless changes. MEDIUM findings never block, and HIGH findings in test folders are downgraded.
• It doesn't replace backups, code review or a staging environment.
• Local hooks can be bypassed with --no-verify, so the CI check is the real enforcement.
• Tested on Linux. macOS should behave the same but wasn't tested. Windows is untested (use Git Bash or WSL for the hook).
• Files and docs are in English.
License: use it in any number of your own, your employer's or your clients' projects, including commercial ones, and commit it to those repos. Please don't resell or redistribute the kit.
Not affiliated with or endorsed by Anthropic, Cursor (Anysphere), OpenAI or GitHub. Product names are used only to describe compatibility.