GitHub Environment Secrets Management Tool - Automate uploading secrets from .env files to GitHub environments
- Bulk Upload: Upload multiple secrets from
.envor similar files to GitHub environments - Individual Secret Management: Create, update, and delete individual secrets
- Environment Support: Manage secrets across different GitHub environments (staging, production, etc.)
- Secure Encryption: Uses GitHub's public key encryption for secure secret storage
- Progress Tracking: Visual progress bars for bulk operations
- Token Validation: Automatic GitHub token validation and session management
- Cross-Platform: Works on macOS, Linux, and Windows
pip install ghvaultgit clone https://github.com/aoamusat/ghvault.git
cd ghvault
pip install -e .git clone https://github.com/aoamusat/ghvault.git
cd ghvault
uv syncYou need a GitHub Personal Access Token with the following permissions:
repo(Full control of private repositories)admin:repo_hook(Read and write repository hooks)
export GH_TOKEN=your_github_token_hereIf no token is found in environment variables, ghvault will prompt you to enter it interactively.
Ensure your GitHub repository has environments configured:
- Go to your repository β Settings β Environments
- Create environments (e.g.,
staging,production) - Configure environment protection rules as needed
ghvault --helpghvault set <environment> <secret_name> <secret_value> --owner <owner> --repo <repo>Example:
ghvault set production DATABASE_URL "postgresql://user:pass@host:5432/db" --owner myorg --repo myappghvault bulk <environment> --env-file .env --owner <owner> --repo <repo>Example:
ghvault bulk staging --env-file .env.staging --owner myorg --repo myappghvault list <environment> --owner <owner> --repo <repo>Example:
ghvault list production --owner myorg --repo myappghvault delete <environment> <secret_name> --owner <owner> --repo <repo>Example:
ghvault delete staging OLD_API_KEY --owner myorg --repo myappghvault delete-bulk <environment> --secrets-file secrets_to_delete.txt --owner <owner> --repo <repo>Example:
ghvault delete-bulk production --secrets-file cleanup.txt --owner myorg --repo myapp# Database Configuration
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
DATABASE_PASSWORD=super_secret_password
# API Keys
STRIPE_SECRET_KEY=sk_test_123456789
SENDGRID_API_KEY=SG.abc123def456
# Feature Flags
ENABLE_FEATURE_X=true
DEBUG_MODE=falseDATABASE_PASSWORD
OLD_API_KEY
DEPRECATED_SECRET
TEMP_TOKEN
- Encryption: All secrets are encrypted using GitHub's public key before transmission
- Token Validation: Automatic validation of GitHub tokens before operations
- Secure Input: Hidden input for sensitive token entry
- No Local Storage: Tokens are only stored in memory during session
- HTTPS Only: All API communications use HTTPS
- Python 3.10+
- uv (recommended) or pip
git clone https://github.com/aoamusat/ghvault.git
cd ghvault
uv sync
source .venv/bin/activate # On Windows: .venv\Scripts\activate# Install test dependencies
uv sync --extra test
# Run all tests
pytest# Run unit tests only
pytest -m "unit or not integration"
# Run integration tests only
pytest -m integration
# Run with coverage report
pytest --cov=ghvault --cov-report=html --cov-report=term-missing
# Run specific test file
pytest tests/test_api.py
# Run specific test class
pytest tests/test_api.py::TestTokenManagement
# Run specific test method
pytest tests/test_api.py::TestTokenManagement::test_set_github_token# Run all tests
make test
# Run with coverage
make test-cov
# Run unit tests only
make test-unit
# Run integration tests only
make test-integration
# Run fast (stop on first failure)
make test-fast# Run all checks (format, lint, type-check, tests)
python run_tests.py
# Run specific test type
python run_tests.py --type unit
python run_tests.py --type integration
python run_tests.py --type coverage
python run_tests.py --type lint
# Run in verbose mode
python run_tests.py --verbose
# Stop on first failure
python run_tests.py --fasttests/test_api.py- Tests for API functionality (GitHub API interactions)tests/test_cli.py- Tests for CLI commands and user interfacetests/test_integration.py- End-to-end integration teststests/conftest.py- Shared fixtures and test configuration
After running tests with coverage, you can view detailed reports:
# Generate HTML coverage report
pytest --cov=ghvault --cov-report=html
# Open coverage report in browser (macOS)
open htmlcov/index.html
# View coverage in terminal
pytest --cov=ghvault --cov-report=term-missing# Install development tools
uv add --dev black isort flake8 mypy
# Format code
black .
isort .
# Lint code
flake8 .
mypy .- click (>=8.2.1): Command-line interface creation
- httpx (>=0.28.1): HTTP client for GitHub API calls
- pynacl (>=1.5.0): Cryptographic library for secret encryption
- tqdm (>=4.67.1): Progress bars for bulk operations
- typer (>=0.16.1): Modern CLI framework
The project includes GitHub Actions workflows for:
- Automated Testing: Run tests on multiple Python versions
- PyPI Publishing: Automatic publishing to PyPI on tagged releases
- TestPyPI Publishing: Publishing to TestPyPI on every push
- Update version in
pyproject.toml - Create and push a git tag:
git tag v0.1.0 git push origin v0.1.0
- GitHub Actions will automatically build and publish to PyPI
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
pytest) - Format code (
black . && isort .) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# 1. Set up environment
export GH_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
# 2. Create .env file
cat > .env.production << EOF
DATABASE_URL=postgresql://prod:secret@db.example.com:5432/app
REDIS_URL=redis://redis.example.com:6379/0
API_SECRET_KEY=prod-secret-key-12345
STRIPE_LIVE_KEY=sk_live_abcdef123456
EOF
# 3. Upload all secrets to production environment
ghvault bulk production --env-file .env.production --owner mycompany --repo myapp
# 4. Verify secrets were uploaded
ghvault list production --owner mycompany --repo myapp
# 5. Update individual secret
ghvault set production API_VERSION "v2.1" --owner mycompany --repo myapp
# 6. Clean up old secrets
echo "OLD_API_KEY" > cleanup.txt
echo "DEPRECATED_TOKEN" >> cleanup.txt
ghvault delete-bulk production --secrets-file cleanup.txt --owner mycompany --repo myapp# .github/workflows/deploy.yml
name: Deploy Secrets
on:
push:
branches: [main]
jobs:
deploy-secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install ghvault
run: pip install ghvault
- name: Deploy secrets to staging
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
ghvault bulk staging --env-file .env.staging --owner ${{ github.repository_owner }} --repo ${{ github.event.repository.name }}Token Permission Error
β Failed to validate token: 403 Forbidden
- Ensure your token has
repoandadmin:repo_hookpermissions - Check that the repository exists and you have access
Environment Not Found
β Environment 'production' not found
- Create the environment in GitHub: Repository β Settings β Environments
- Ensure the environment name matches exactly (case-sensitive)
Invalid .env File
β Failed to parse .env file
- Check file format:
KEY=value(no spaces around=) - Ensure file exists and is readable
- Avoid quotes unless they're part of the value
Set environment variable for verbose output:
export GHVAULT_DEBUG=1
ghvault bulk production --env-file .envThis project is licensed under the MIT License - see the LICENSE file for details.
- GitHub API for providing robust secrets management
- The Python community for excellent libraries
- Contributors and users who help improve this tool
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Wiki
Made with β€οΈ for the GitHub community