A safe wrapper around rm that prevents catastrophic system deletions.
Tired of fearing every rm -rf command? dontrm is a drop-in replacement for rm that blocks dangerous operations like rm -rf / or rm -rf /etc/* while allowing normal file deletions to proceed safely.
- Top-level system directories:
/,/bin,/boot,/dev,/etc,/lib,/lib64,/opt,/proc,/root,/run,/sbin,/srv,/sys,/usr,/var - System directory wildcards:
/usr/bin/*,/etc/*, etc. - Works even with sudo: Protection cannot be bypassed with elevated privileges
- Works with common flags:
-rf,--no-preserve-root, etc.
- User home directories:
/home/usercan be deleted (by design) - Data directories:
/data,/mnt,/mediadirectories - Specific files: Individual files in system directories like
/etc/passwd - Subdirectories: Subdirectories like
/usr/bin/go/* - Symlink following: Symlinks that resolve to protected paths
See SECURITY.md for complete details on protection scope and limitations.
Visit https://dontrm.fuabioo.com/#installation for the latest installation script.
Prerequisites: Go 1.25+
# Clone the repository
git clone https://github.com/Fuabioo/dontrm.git
cd dontrm
# Build and install
go build -ldflags="-s -w" -o dontrm .
sudo mv dontrm /usr/bin/dontrm
# Or use just (if installed)
just build
just installTo make rm use dontrm automatically, add an alias to your shell configuration:
Bash (~/.bashrc):
alias rm='dontrm'
alias unsafe-rm='/usr/bin/rm' # Keep access to real rm (use with EXTREME caution)Zsh (~/.zshrc):
alias rm='dontrm'
alias unsafe-rm='/usr/bin/rm'Fish (~/.config/fish/config.fish):
alias rm 'dontrm'
alias unsafe-rm '/usr/bin/rm'Sh/Dash (~/.profile):
alias rm='dontrm'
alias unsafe-rm='/usr/bin/rm'After adding the alias, restart your shell or source the config file:
source ~/.bashrc # For bash
source ~/.zshrc # For zsh
source ~/.profile # For sh/dash
# For fish, just restart the shellBy default, sudo rm won't use your alias because sudo runs commands in a clean environment. Here are shell-agnostic approaches to make sudo rm use dontrm:
Option 1: System-Wide Installation (Recommended - Works for All Shells)
Install dontrm system-wide so it's available to all users including root:
# Build dontrm
go build -ldflags="-s -w" -o dontrm .
# Install to system location
sudo install -m 755 dontrm /usr/local/bin/dontrm
# Optional: Create symlink so 'rm' points to dontrm
sudo ln -sf /usr/local/bin/dontrm /usr/local/bin/rm
# Ensure /usr/local/bin is in PATH before /usr/bin
# Add to /etc/environment or /etc/profile:
export PATH="/usr/local/bin:$PATH"Pros: Works immediately for all users, all shells, and sudo commands
Cons: System-wide change affects all users
Security: High - no shell configuration needed
Option 2: Shell-Specific Alias for Root User
Add an alias to root's shell configuration. Note: This only works for interactive sudo shells (sudo -i, sudo -s, sudo bash), not for direct commands like sudo rm file.txt.
For Bash (root's ~/.bashrc or /root/.bashrc):
sudo tee -a /root/.bashrc >/dev/null <<'EOF'
# Use dontrm instead of rm
alias rm='dontrm'
EOFFor Zsh (root's /root/.zshrc):
sudo tee -a /root/.zshrc >/dev/null <<'EOF'
# Use dontrm instead of rm
alias rm='dontrm'
EOFFor Fish (root's /root/.config/fish/config.fish):
# Create config directory if it doesn't exist
sudo mkdir -p /root/.config/fish
# Add alias
sudo tee -a /root/.config/fish/config.fish >/dev/null <<'EOF'
# Use dontrm instead of rm
alias rm 'dontrm'
EOFPros: Simple, doesn't affect non-sudo commands
Cons: Only works for sudo -i or sudo bash, not sudo rm file.txt
Security: High - isolated to root's shell
Option 3: Alias Expansion in Bash/Zsh (Shell-Specific)
Add to your user's shell config (~/.bashrc or ~/.zshrc):
alias sudo='sudo ' # Trailing space makes sudo expand aliasesPros: Works for sudo rm file.txt commands
Cons: Only works in bash/zsh, affects ALL sudo commands, can cause unexpected behavior
Security: Medium - changes sudo behavior globally
Option 4: Configure sudoers (Advanced - Shell Agnostic)
Preserve environment variables through sudo by editing /etc/sudoers:
# Edit sudoers safely
sudo visudo
# Add this line to preserve alias-related environment
Defaults env_keep += "BASH_FUNC_*"Pros: Shell-agnostic Cons: Complex, security trade-offs, unreliable Security: Lower - preserves environment variables
| Approach | Direct sudo rm |
Interactive sudo -i |
Shell Agnostic | Complexity | Recommended |
|---|---|---|---|---|---|
| System-wide install | β Yes | β Yes | β Yes | Medium | β Best |
| Root shell alias | β No | β Yes | β Yes | Easy | β Good |
| Alias expansion | β Yes* | β Yes | β No (bash/zsh only) | Easy | |
| sudoers config | β Yes | Hard | β Avoid |
*Only for bash/zsh
# Test regular dontrm (works for all methods)
dontrm version
# Expected output: DON'T rm! dev
# Test sudo with interactive shell (works for Options 1 & 2)
sudo -i
rm version # Should show "DON'T rm!" not GNU rm
exit
# Test direct sudo rm (only works for Options 1 & 3)
DRY_RUN=1 sudo rm -rf /etc
# Expected: β Blocked dangerous operation
# If you see GNU rm output or actual deletion attempts, the alias isn't workingTroubleshooting:
- If
sudo rmshows GNU rm, trysudo -ithenrmto test if the root alias works - For fish users: Shell aliases don't transfer to sudo by default - use Option 1 (system-wide install)
- Verify dontrm is installed:
which dontrmandsudo which dontrm
# Check version
dontrm version
# Delete a file normally
dontrm file.txt
# Delete directory recursively
dontrm -rf ./old-project/
# This will be BLOCKED
dontrm -rf /etc
# Error: β Blocked dangerous operation: known top level match: /etc
# This will also be BLOCKED
sudo dontrm -rf /
# Error: β Blocked dangerous operation: known top level match: /Always test dangerous-looking commands with DRY_RUN first:
# Test mode - checks safety but doesn't actually delete
DRY_RUN=1 dontrm -rf /some/path/
# If no error, run for real
dontrm -rf /some/path/DRY_RUN accepts 1, true, or any truthy value.
dontrm supports the following environment variables for customization:
- Description: Test mode - performs safety checks but doesn't execute deletions
- Values:
1,true(case-insensitive) - Default: Not set (deletions execute normally)
- Example:
DRY_RUN=1 dontrm -rf /some/path/
- Description: Custom path to the
rmbinary - Values: Absolute path to
rmexecutable - Default: Automatically detected via
PATHlookup - Use Case: Custom
rminstallations or testing - Example:
DONTRM_RM_PATH=/bin/rm dontrm file.txt
dontrm works on:
- Linux (all distributions)
- macOS (automatically finds
rmin/bin/rmor/usr/bin/rm) - Windows (limited - requires WSL or Cygwin with
rminstalled)
The rm binary is automatically detected using your system's PATH. If you have a custom rm installation, use the DONTRM_RM_PATH environment variable to specify its location.
Platform-Specific Notes:
- Linux: Default
rmpath is typically/usr/bin/rmor/bin/rm - macOS: Default
rmpath is typically/bin/rm - Custom installations: Set
DONTRM_RM_PATHto yourrmlocation
- Argument Validation: Before executing any deletion,
dontrminspects all arguments - Pattern Matching: Checks arguments against known dangerous system paths
- Glob Expansion: Evaluates wildcards to detect if they expand to system directories
- Safety First: If any dangerous pattern is detected, operation is blocked with clear error
- Otherwise, Execute: If safe, locates
rmin your PATH and executes it with the arguments
βββββββββββββββ
β dontrm args β
ββββββββ¬βββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Check system paths? βββββ YES βββΆ BLOCK β
βββββββββββββ¬ββββββββββββββ
β
NO
β
βΌ
βββββββββββββββββββββββββββ
β Check glob expansions? βββββ YES βββΆ BLOCK β
βββββββββββββ¬ββββββββββββββ
β
NO
β
βΌ
βββββββββββββββββββββββββββ
β Find rm in PATH β
βββββββββββββ¬ββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Execute rm with args βββββ β
βββββββββββββββββββββββββββ
- Go 1.25+
- Docker (required for testing)
justcommand runner (recommended)- golangci-lint
CRITICAL: All tests run in Docker containers for safety. Never run go test directly.
# Run unit tests (Go tests in Docker)
just test
# Run E2E tests (tests actual binary in bash/zsh/fish)
just e2e
# Run all tests (unit + E2E)
just test-all
# Check coverage (requires 85% minimum)
just coverage
# Run linting
just lintSee TESTING.md for comprehensive testing documentation.
# Build binary
just build
# Clean artifacts
just clean
# Rebuild Docker test images
just rebuild-test-image
just rebuild-e2e-imageThis project employs defense-in-depth testing:
-
Unit Tests: Go tests validate logic correctness (87.3% coverage)
- Run in Docker with control file safety check
- Test argument parsing, pattern matching, edge cases
-
E2E Tests: Bash script tests validate real-world usage
- Tests actual compiled binary in Ubuntu environment
- Validates bash, zsh, and fish compatibility
- Tests sudo usage, exit codes, error messages
- Creates and deletes real files (safely in Docker)
Both test suites run exclusively in Docker and cannot execute on host machines (enforced by control file checks).
We welcome contributions! Please see CONTRIBUTING.md for detailed guidelines.
Quick contributing checklist:
- β
All tests pass (
just test-all) - β
Coverage β₯ 85% (
just coverage) - β
Linting passes (
just lint) - β Tests run in Docker (enforced automatically)
This project deals with dangerous file operations. Security is our top priority.
- See SECURITY.md for security policy
- Report vulnerabilities to: fabio@fuabioo.com
- All tests run in isolated Docker containers
- Multiple safety layers prevent accidental host PC damage
- TESTING.md - Comprehensive testing guide, Docker safety mechanisms
- CONTRIBUTING.md - Development setup, workflow, code standards
- SECURITY.md - Security policy, protection scope, vulnerability reporting
Yes, by calling /usr/bin/rm directly. dontrm is designed to prevent accidents, not malicious actions. If you really need to delete system files, use the real rm directly (but please don't).
Negligibly. Validation adds ~1-2ms overhead for simple operations. For recursive operations on thousands of files, the actual deletion time far exceeds validation time.
By design, users should have full control over their home directories. The goal is to prevent system-destroying operations, not restrict legitimate user file management.
Not currently. Protection list is hardcoded based on standard Linux FHS (Filesystem Hierarchy Standard). See the TODO section for planned features.
Track progress and suggest features in GitHub Issues.
Planned features:
- Configurable protection paths (config file support)
- Verbose/debug mode for troubleshooting
- Interactive mode (confirm before deletion)
- Trash/recycle bin functionality
- Plugin system for custom safety rules
Completed:
- Comprehensive test suite with Docker isolation
- CI/CD with automated testing
- E2E tests with multi-shell support
- Cross-platform builds (Linux/macOS/Windows)
MIT License - see LICENSE for details.
Inspired by countless stories of sudo rm -rf / disasters across the internet. This is a small attempt to prevent future tragedies.
dontrm is a safety net, not a security tool. Always double-check commands, maintain backups, and use DRY_RUN=1 when in doubt.