Effortless file encryption for your git repos—pattern-matched, secure, and keyfile-flexible.
Project description
git-safe
A Python CLI tool providing file encryption with .gitattributes-style pattern matching and both symmetric and GPG-encrypted keyfile modes.
Effortless file encryption for your git repos—pattern-matched, secure, and keyfile-flexible.
🔒 Secure by Design: Built with modern cryptographic standards and comprehensive security scanning
Table of Contents
- Features
- Quick Start
- Installation
- Usage
- Configuration
- Examples
- Architecture
- Security
- Contributing
- License
Quick Start
# Install from PyPI
pip install gitsafe-cli
# Or install from source
git clone https://github.com/hemonserrat/git-safe.git
cd git-safe
pip install -e .
# Initialize encryption for your repository (automatically sets up .gitattributes and Git filters)
git-safe init
# That's it! Files matching *.secret are now automatically encrypted/decrypted transparently
echo "my secret" > config.secret
git add config.secret # Automatically encrypted when committed
git commit -m "Add secret config"
# File remains readable in your working directory, encrypted in Git history
Features
- Transparent Operation: Files are automatically encrypted/decrypted through Git filters - no manual intervention needed
- Pattern Matching: Uses
.gitattributes-style patterns for selecting files to encrypt - Dual Encryption Modes:
- Symmetric encryption (AES-256 CTR + HMAC-SHA256)
- GPG-encrypted keyfile export/import (like git-crypt's
export-key)
- Modular Architecture: Clean separation of concerns with dedicated modules
- Enhanced CLI: Multiple commands for different operations
- File Integrity: HMAC verification for encrypted files
- Backup Support: Optional backup creation during manual encryption
Installation
From PyPI (Recommended)
pip install gitsafe-cli
From Source
git clone https://github.com/hemonserrat/git-safe.git
cd git-safe
pip install -e .
Development Installation
git clone https://github.com/hemonserrat/git-safe.git
cd git-safe
pip install -e ".[dev,security]"
System Requirements
- Python 3.8 or higher
- GPG (for keyfile sharing functionality)
- Ubuntu/Debian:
sudo apt-get install gnupg - macOS:
brew install gnupg - Windows: Install Gpg4win
- Ubuntu/Debian:
Usage
Initialize a new keyfile
git-safe init [--keyfile PATH] [--force] [--export-gpg RECIPIENT]
The init command performs the following setup automatically:
- Creates keyfile: By default at
.git-safe/.git-safe-key(creates.git-safedirectory if needed) - Sets up .gitattributes: Adds
*.secret filter=git-safe diff=git-safeif not already present - Configures Git filters: Sets up local Git configuration for automatic encryption/decryption:
filter.git-safe.clean- Encrypts files on commitfilter.git-safe.smudge- Decrypts files on checkoutfilter.git-safe.required- Makes the filter requireddiff.git-safe.textconv- Enables readable diffs
Note: Git filter setup is skipped if not in a Git repository, with a warning message.
🔐 CRITICAL SECURITY WARNING
The
.git-safedirectory contains your encryption keys and MUST be kept secure:
- Add
.git-safe/to your.gitignore- Never commit keyfiles to your repository- Backup your keyfiles securely - If lost, encrypted files cannot be recovered
- Use GPG export for team sharing - Share keys securely with
git-safe export-keyWithout the keyfile, your encrypted data is permanently inaccessible!
Transparent Operation
After initialization, git-safe works transparently through Git filters:
# Files matching *.secret are automatically encrypted/decrypted
echo "database_password=secret123" > config.secret
git add config.secret # Automatically encrypted when staged
git commit -m "Add config" # Stored encrypted in Git history
cat config.secret # Still readable in working directory
# No manual encrypt/decrypt needed - it's all automatic!
Export keyfile with GPG encryption
git-safe export-key RECIPIENT [--keyfile PATH] [--output PATH]
Import GPG-encrypted keyfile
git-safe unlock [--gpg-keyfile PATH] [--output PATH]
- By default, the unlock command will look for
.git-safe/.git-safe-key.gpgif--gpg-keyfileis not specified.
Manual Operations (Optional)
The following commands are optional - Git filters handle encryption/decryption automatically:
Encrypt files manually
git-safe encrypt [--keyfile PATH] [--no-backup] [--continue-on-error]
Decrypt files manually
git-safe decrypt [--keyfile PATH] [--all] [--continue-on-error] [PATTERNS...]
- Decrypted files will always overwrite the original encrypted files in-place, preserving their names and extensions.
Show status of encrypted files
git-safe status [--keyfile PATH]
Clean backup files
git-safe clean
.gitattributes Configuration
The git-safe init command automatically adds the default pattern *.secret filter=git-safe diff=git-safe to your .gitattributes file.
You can add additional patterns to specify which files should be encrypted:
secrets.txt filter=git-safe
*.key filter=git-safe
config/*.secret filter=git-safe
Note: The diff=git-safe attribute enables readable diffs for encrypted files when the Git filter is properly configured.
Architecture
The tool is organized into several modules:
constants.py: Magic headers and cryptographic constantscrypto.py: Low-level cryptographic operations (AES-CTR, HMAC)keyfile.py: Keyfile generation, loading, and GPG export/importpatterns.py: .gitattributes parsing and pattern matchingfile_ops.py: File encryption, decryption, and managementcli.py: Command-line interface and argument parsing
File Format
Encrypted files use the format:
MAGIC (9 bytes) + NONCE (12 bytes) + ENCRYPTED_DATA
Keyfiles use the format:
KEYFILE_MAGIC (12 bytes) + KEY_BLOBS
Where each key blob is:
ID (4 bytes) + LENGTH (4 bytes) + DATA (LENGTH bytes)
Security
Encryption Details
- Uses AES-256 in CTR mode for encryption
- HMAC-SHA256 for integrity verification
- Secure random nonce generation
- GPG integration for keyfile sharing
- Restrictive file permissions (0600) for keyfiles
Keyfile Management (CRITICAL)
⚠️ WARNING: Keyfile loss means permanent data loss!
Essential Security Practices:
-
Never commit keyfiles to Git:
echo ".git-safe/" >> .gitignore git add .gitignore git commit -m "Ignore git-safe keyfiles"
-
Backup keyfiles securely:
- Store copies in secure, encrypted locations
- Use multiple backup locations (local + cloud)
- Test backup restoration regularly
-
Team collaboration:
# Export for team members git-safe export-key teammate@company.com # Team member imports git-safe unlock --gpg-keyfile shared-key.gpg
-
Key rotation:
- Regularly rotate keyfiles for long-term projects
- Use
--forceflag to overwrite existing keyfiles - Re-encrypt all files after key rotation
Recovery Scenarios:
- ✅ Keyfile backed up: Restore from backup, continue working
- ❌ Keyfile lost, no backup: Encrypted files are permanently unrecoverable
- ✅ Team member has keyfile: Export/import via GPG
Compatibility
This tool is designed to be compatible with git-crypt's file format and workflow, while providing additional features and a more Pythonic implementation.
Legacy Interface
The original git-safe.py script is maintained for backward compatibility and now uses the new modular architecture internally.
Examples
- Complete setup with transparent encryption:
# Initialize keyfile (automatically sets up .gitattributes and Git filters)
git-safe init
# Add .git-safe to .gitignore (IMPORTANT!)
echo ".git-safe/" >> .gitignore
# Create secret files - they work transparently
echo "database_password=secret123" > config.secret
echo "api_key=abc123xyz" > api.secret
# Normal Git workflow - encryption happens automatically
git add .
git commit -m "Add configuration files"
# Files are encrypted in Git, readable in working directory
git show HEAD:config.secret # Shows encrypted binary data
cat config.secret # Shows readable plaintext
- Share keyfile with team member:
# Export keyfile for GPG recipient
git-safe export-key alice@example.com
# Team member imports the keyfile
git-safe unlock
# By default, this will look for .git-safe/.git-safe-key.gpg
- Manual operations (if needed):
# Manually encrypt files (usually not needed)
git-safe encrypt
# Manually decrypt files (usually not needed)
git-safe decrypt --all
# Check status of encrypted files
git-safe status
Contributing
We welcome contributions! Please see our Contributing Guidelines for details.
Development Setup
git clone https://github.com/hemonserrat/git-safe.git
cd git-safe
pip install -e ".[dev,security]"
pre-commit install # Optional: for automated code formatting
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=git_safe --cov-report=html
# Run security tests
bandit -r git_safe/
safety check
Troubleshooting
Common Issues
GPG not found: Ensure GPG is installed and available in your PATH.
gpg --version # Should show GPG version
Permission denied: Keyfiles are created with restrictive permissions (0600). Ensure you have proper file system permissions.
Import errors: If you encounter import errors, try reinstalling:
pip uninstall gitsafe-cli
pip install gitsafe-cli
Keyfile Issues
"No keyfile found" error:
# Check if keyfile exists
ls -la .git-safe/.git-safe-key
# If missing, restore from backup or re-initialize
git-safe init --force
Git filter errors:
# Check Git filter configuration
git config --local --list | grep git-safe
# Re-run init to fix configuration
git-safe init --force
Files not encrypting automatically:
# Check .gitattributes
cat .gitattributes
# Verify file matches pattern
echo "test.secret" | git check-attr --all --stdin
Encrypted files show as binary in diffs:
# Check diff filter configuration
git config --local diff.git-safe.textconv
# Should show: git-safe diff
Changelog
See CHANGELOG.md for a detailed history of changes.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Inspired by git-crypt by Andrew Ayer
- Built with modern Python cryptographic libraries
- Thanks to all contributors who have helped improve this project
Dependencies
- cryptography - Modern cryptographic operations
- python-gnupg - GPG integration
- pathspec - .gitattributes pattern matching
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gitsafe_cli-1.0.1.tar.gz.
File metadata
- Download URL: gitsafe_cli-1.0.1.tar.gz
- Upload date:
- Size: 38.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
152f9621440500d08f5a0688cca13a6942bf2971909d5c8b7e78e32462a75529
|
|
| MD5 |
2362b8544970e81bf241ba733458fa5b
|
|
| BLAKE2b-256 |
06c67ef28f6bb47d86f762c96d6045fa0132566b6b40a9df52fd77dadefa02bf
|
Provenance
The following attestation bundles were made for gitsafe_cli-1.0.1.tar.gz:
Publisher:
release.yml on hemonserrat/git-safe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gitsafe_cli-1.0.1.tar.gz -
Subject digest:
152f9621440500d08f5a0688cca13a6942bf2971909d5c8b7e78e32462a75529 - Sigstore transparency entry: 510759314
- Sigstore integration time:
-
Permalink:
hemonserrat/git-safe@3bf1f9608e5a3e3e1f47ed929a4b201af54aac0a -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/hemonserrat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3bf1f9608e5a3e3e1f47ed929a4b201af54aac0a -
Trigger Event:
push
-
Statement type:
File details
Details for the file gitsafe_cli-1.0.1-py3-none-any.whl.
File metadata
- Download URL: gitsafe_cli-1.0.1-py3-none-any.whl
- Upload date:
- Size: 19.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cd4560bbfc25dd7ba5ca82795ec99a4832c13deb4efeac08994e27670ec5b67
|
|
| MD5 |
b26054163a72b2189891a28074505519
|
|
| BLAKE2b-256 |
49bff517ccf72537a2cc6b4bde4cc314719fc3fd59deb9d42cd832d4ebe58c0b
|
Provenance
The following attestation bundles were made for gitsafe_cli-1.0.1-py3-none-any.whl:
Publisher:
release.yml on hemonserrat/git-safe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gitsafe_cli-1.0.1-py3-none-any.whl -
Subject digest:
8cd4560bbfc25dd7ba5ca82795ec99a4832c13deb4efeac08994e27670ec5b67 - Sigstore transparency entry: 510759357
- Sigstore integration time:
-
Permalink:
hemonserrat/git-safe@3bf1f9608e5a3e3e1f47ed929a4b201af54aac0a -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/hemonserrat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3bf1f9608e5a3e3e1f47ed929a4b201af54aac0a -
Trigger Event:
push
-
Statement type: