diff --git a/.devcontainer/CHANGELOG.md b/.devcontainer/CHANGELOG.md index 8573d41..3489f13 100644 --- a/.devcontainer/CHANGELOG.md +++ b/.devcontainer/CHANGELOG.md @@ -2,6 +2,14 @@ ## [Unreleased] +### Fixed + +#### Dangerous Command Blocker +- **Force push block now suggests `git merge` as workaround** — error message explains how to avoid diverged history instead of leaving the agent to improvise destructive workarounds +- **Block `--force-with-lease`** — was slipping through regex; all force push variants now blocked uniformly +- **Block remote branch deletion** — `git push origin --delete` and colon-refspec deletion (`git push origin :branch`) now blocked; deleting remote branches closes associated PRs +- **Fixed README** — error handling was documented as "fails open" but code actually fails closed; corrected to match behavior + ### Added #### Documentation diff --git a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md index d7c8371..bac3ed0 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md +++ b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md @@ -14,7 +14,8 @@ Inspects every Bash command Claude attempts to run against a set of dangerous pa | Privileged deletion | `sudo rm` | | World-writable permissions | `chmod 777`, `chmod -R 777` | | Force push to main/master | `git push --force origin main`, `git push -f origin master` | -| Bare force push | `git push -f`, `git push --force` (no branch specified) | +| Bare force push | `git push -f`, `git push --force`, `git push --force-with-lease` | +| Remote branch deletion | `git push origin --delete`, `git push origin :branch` | | Git history destruction | `git reset --hard origin/main`, `git clean -f` | | System directory writes | `> /usr/`, `> /etc/`, `> /bin/`, `> /sbin/` | | Disk formatting | `mkfs.*`, `dd of=/dev/` | @@ -47,7 +48,7 @@ Claude calls the Bash tool ### Error Handling - **JSON parse failure**: Fails closed (exit 2) — if the input can't be read, the command is blocked -- **Other exceptions**: Fails open (exit 0) — logs the error to stderr but does not block +- **Other exceptions**: Fails closed (exit 2) — logs the error to stderr and blocks ### Timeout diff --git a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py index 1bebdf3..5f45e46 100644 --- a/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +++ b/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py @@ -11,6 +11,13 @@ import re import sys +FORCE_PUSH_SUGGESTION = ( + "Blocked: force push is not allowed. " + "If you rebased and need to update a remote branch, use " + "`git merge origin/main` instead of `git rebase` to avoid " + "diverged history that requires force push." +) + DANGEROUS_PATTERNS = [ # Destructive filesystem deletion ( @@ -79,16 +86,30 @@ (r"\brm\s+.*-[^\s]*r[^\s]*f[^\s]*\s+\.\./", "Blocked: rm -rf on parent directory"), (r"\bfind\s+.*-exec\s+rm\b", "Blocked: find -exec rm is dangerous"), (r"\bfind\s+.*-delete\b", "Blocked: find -delete is dangerous"), - # Git history destruction - (r"\bgit\s+push\s+-f\b", "Blocked: bare force push - specify remote and branch"), - ( - r"\bgit\s+push\s+--force\b", - "Blocked: bare force push - specify remote and branch", - ), + # Git history destruction — force push (all variants) + (r"\bgit\s+push\s+-f\b", FORCE_PUSH_SUGGESTION), + (r"\bgit\s+push\s+--force\b", FORCE_PUSH_SUGGESTION), + (r"\bgit\s+push\s+--force-with-lease\b", FORCE_PUSH_SUGGESTION), ( r"\bgit\s+clean\s+-[^\s]*f", "Blocked: git clean -f removes untracked files permanently", ), + # Remote branch deletion — closes open PRs and destroys remote history + ( + r"\bgit\s+push\s+\S+\s+--delete\b", + "Blocked: deleting remote branches closes any associated pull requests. " + "Do not delete remote branches as a workaround for force push blocks.", + ), + ( + r"\bgit\s+push\s+--delete\b", + "Blocked: deleting remote branches closes any associated pull requests. " + "Do not delete remote branches as a workaround for force push blocks.", + ), + ( + r"\bgit\s+push\s+\S+\s+:\S", + "Blocked: push with colon-refspec deletes remote branches and closes " + "associated pull requests. Do not use as a workaround for force push blocks.", + ), ]