Reviewed-on: #5
chguard
chguard is a safety-first command-line tool that snapshots and restores filesystem ownership and permissions.
Think of it as a guardrail around chmod and chown:
it records the current state, shows you exactly what would change, and only
applies changes after explicit confirmation.
Features
Snapshots ownership and permissions
Records numeric uid, gid, and file mode for files and directories.
Preview before restore
Always shows a clear, readable table of differences before applying changes.
Interactive confirmation
A single confirmation prompt at the end of a restore (default: No).
Dry-run mode
Preview restore operations without prompting or applying changes.
Wrapper mode (automatic snapshots)
chguard can also run as a wrapper around ownership and permission commands.
In this mode, chguard automatically saves a snapshot before the command runs, so the user can easily restore the previous state if needed.
Supported commands
Wrapper mode is intentionally limited to commands that modify filesystem metadata only:
chownchmodchgrp
Other commands are rejected to avoid giving a false sense of protection.
Automatic snapshot names
Snapshots created in wrapper mode are named automatically, for example:
auto-20251230-161301
Auto-generated snapshots are visually distinguished in the output so they are easy to identify.
Scope control
Restore:
- both ownership and permissions (default)
- permissions only
- ownership only
Safe by design
- Never creates, deletes, or moves files
- Missing files are ignored
- New files are ignored
- Symbolic links are skipped entirely
- Requires sudo only when necessary
Non-Goals
chguard deliberately does not:
- restore deleted files
- remove newly created files
- track file contents or checksums
- manage ACLs or extended attributes
- provide full “undo” semantics
It only concerns itself with ownership and permissions.
Installation
From GuardUtils package repo
This is the preferred method of installation.
Debian/Ubuntu
1) Import the GPG key
sudo mkdir -p /usr/share/keyrings
curl -fsSL https://repo.sysmd.uk/guardutils/guardutils.gpg | sudo gpg --dearmor -o /usr/share/keyrings/guardutils.gpg
The GPG fingerprint is 0032C71FA6A11EF9567D4434C5C06BD4603C28B1.
2) Add the APT source
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/guardutils.gpg] https://repo.sysmd.uk/guardutils/debian stable main" | sudo tee /etc/apt/sources.list.d/guardutils.list
3) Update and install
sudo apt update
sudo apt install chguard
Fedora/RHEL
1) Import the GPG key
sudo rpm --import https://repo.sysmd.uk/guardutils/guardutils.gpg
2) Add the repository configuration
sudo tee /etc/yum.repos.d/guardutils.repo > /dev/null << 'EOF'
[guardutils]
name=GuardUtils Repository
baseurl=https://repo.sysmd.uk/guardutils/rpm/$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://repo.sysmd.uk/guardutils/guardutils.gpg
EOF
4) Update and install
sudo dnf upgrade --refresh
sudo dnf install chguard
From PyPI
pip install chguard
From this repository
git clone https://git.sysmd.uk/guardutils/chguard.git
cd chguard/
poetry install
This installs the chguard CLI into the Poetry environment.
Usage
Save a state
chguard --save /srv/app --name app-baseline
If the path contains root-owned files, saving requires sudo.
List saved states
chguard --list
Example output:
app-baseline /srv/app 2025-12-20 18:11:08 +00:00
Restore a state (preview only)
chguard --restore app-baseline
This shows a table of ownership and permission differences.
Restore with confirmation
chguard --restore app-baseline
You will be prompted:
Do you want to restore this state? (y/N)
The default answer is No.
Dry-run
chguard --restore app-baseline --dry-run
Restore only permissions or only ownership
chguard --restore app-baseline --permissions
chguard --restore app-baseline --owner
Wrapper mode
Use -- to separate chguard arguments from the wrapped command:
chguard -- chown user:group file
chguard -- chmod 755 file
chguard -- chgrp staff file
Privilege model
chguard never escalates privileges automatically
- Saving fails if root-owned files are present and the user is not root
- Restoring fails if changes require elevated privileges
- Preview and dry-run operations never require sudo
Storage
Snapshots are stored in a local SQLite database containing:
- relative path
- file type (file or directory)
- numeric uid / gid
- numeric mode
Usernames and permission strings are resolved only for display.
TAB completion
Add this to your .bashrc
eval "$(register-python-argcomplete chguard)"
And then
source ~/.bashrc
pre-commit
This project uses pre-commit to run automatic formatting and security checks before each commit (Black, Bandit, and various safety checks).
To enable it:
poetry install
poetry run pre-commit install
This ensures consistent formatting, catches common issues early, and keeps the codebase clean.
