Skip to main content

Effortless file encryption for your git repos—pattern-matched, secure, and keyfile-flexible.

Project description

git-safe

CI Security Scan codecov PyPI version Python versions License: MIT Code style: black Ruff Security: bandit

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

Quick Start

# Install from PyPI
pip install git-safe

# 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 git-safe

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

Usage

Initialize a new keyfile

git-safe init [--keyfile PATH] [--force] [--export-gpg RECIPIENT]

The init command performs the following setup automatically:

  1. Creates keyfile: By default at .git-safe/.git-safe-key (creates .git-safe directory if needed)
  2. Sets up .gitattributes: Adds *.secret filter=git-safe diff=git-safe if not already present
  3. Configures Git filters: Sets up local Git configuration for automatic encryption/decryption:
    • filter.git-safe.clean - Encrypts files on commit
    • filter.git-safe.smudge - Decrypts files on checkout
    • filter.git-safe.required - Makes the filter required
    • diff.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-safe directory 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-key

Without 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.gpg if --gpg-keyfile is 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 constants
  • crypto.py: Low-level cryptographic operations (AES-CTR, HMAC)
  • keyfile.py: Keyfile generation, loading, and GPG export/import
  • patterns.py: .gitattributes parsing and pattern matching
  • file_ops.py: File encryption, decryption, and management
  • cli.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:

  1. Never commit keyfiles to Git:

    echo ".git-safe/" >> .gitignore
    git add .gitignore
    git commit -m "Ignore git-safe keyfiles"
    
  2. Backup keyfiles securely:

    • Store copies in secure, encrypted locations
    • Use multiple backup locations (local + cloud)
    • Test backup restoration regularly
  3. Team collaboration:

    # Export for team members
    git-safe export-key teammate@company.com
    
    # Team member imports
    git-safe unlock --gpg-keyfile shared-key.gpg
    
  4. Key rotation:

    • Regularly rotate keyfiles for long-term projects
    • Use --force flag 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

  1. 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
  1. 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
  1. 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 git-safe
pip install git-safe

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gitsafe_cli-1.0.0.tar.gz (38.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gitsafe_cli-1.0.0-py3-none-any.whl (19.2 kB view details)

Uploaded Python 3

File details

Details for the file gitsafe_cli-1.0.0.tar.gz.

File metadata

  • Download URL: gitsafe_cli-1.0.0.tar.gz
  • Upload date:
  • Size: 38.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for gitsafe_cli-1.0.0.tar.gz
Algorithm Hash digest
SHA256 755cf276fb318106935b5a776a88da2927b30d3d4902095599571e252552ac14
MD5 854bcadd80ee560606687d2273953644
BLAKE2b-256 81c290505a88de3a5e6c7e5ab6b029cdf1ae4c33d857354b8afc96064475f2b4

See more details on using hashes here.

File details

Details for the file gitsafe_cli-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: gitsafe_cli-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 19.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for gitsafe_cli-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 02f8256920e76a591e3a3420e7a4fb986ca7ff30a2bdd43957add5f791c36535
MD5 3bd27271200b9b6cafc80242de9f9ab2
BLAKE2b-256 95282d6d9e00bf1733cef5262797d52a0607b281659b0ae239eba553a031110c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page