Catch config errors before they explode - Python environment variable management with import-time validation, type safety, and secret detection
Project description
╔══════════════════════════╗
║ ━━━━━(○)━━━━━ ║
║ ║
║ T R I P W I R E ║
║ ║
║ Config validation ║
║ that fails fast ║
╚══════════════════════════╝
Smart Environment Variable Management for Python
Catch missing/invalid environment variables at import time (not runtime) with type validation, secret detection, and git history auditing.
The Problem
Every Python developer has experienced this:
# Your code
import os
API_KEY = os.getenv("API_KEY") # Returns None - no error yet
# 2 hours later in production...
response = requests.get(url, headers={"Authorization": f"Bearer {API_KEY}"})
# 💥 TypeError: can only concatenate str (not "NoneType") to str
# Production is down. Users are angry. You're debugging at 2 AM.
The pain:
- Environment variables fail at runtime, not at startup
- No validation (wrong types, missing values, invalid formats)
- .env files drift across team members
- Secrets accidentally committed to git
- No type safety for configuration
The Solution: TripWire
TripWire validates environment variables at import time and keeps your team in sync.
Before TripWire
import os
# Runtime crash waiting to happen
DATABASE_URL = os.getenv("DATABASE_URL") # Could be None
PORT = int(os.getenv("PORT")) # ValueError if PORT not set
DEBUG = os.getenv("DEBUG") == "true" # Wrong! Returns False for "True", "1", etc.
After TripWire
from tripwire import env
# Import fails immediately if vars missing/invalid
DATABASE_URL: str = env.require("DATABASE_URL", format="postgresql")
PORT: int = env.require("PORT", min_val=1, max_val=65535)
DEBUG: bool = env.optional("DEBUG", default=False)
# Your app won't even start with bad config!
Key Benefits:
- ✅ Import-time validation - Fail fast, not in production
- ✅ Type safety - Automatic type coercion with validation
- ✅ Team sync - Keep .env files consistent across team
- ✅ Auto-documentation - Generate .env.example from code
- ✅ Secret detection - 45+ platform-specific patterns (AWS, GitHub, Stripe, etc.)
- ✅ Git history auditing - Find when secrets were leaked and generate remediation steps
- ✅ Great error messages - Know exactly what's wrong and how to fix it
Quick Start
Installation
pip install tripwire-py
Note: The package name on PyPI is
tripwire-py, but you import it astripwire:from tripwire import env # Import name is 'tripwire'
Initialize Your Project
$ tripwire init
Welcome to TripWire! 🎯
✅ Created .env
✅ Created .env.example
✅ Updated .gitignore
Setup complete! ✅
Next steps:
1. Edit .env with your configuration values
2. Import in your code: from tripwire import env
3. Use variables: API_KEY = env.require('API_KEY')
Basic Usage
# config.py
from tripwire import env
# Required variables (fail if missing)
API_KEY: str = env.require("API_KEY")
DATABASE_URL: str = env.require("DATABASE_URL", format="postgresql")
# Optional with defaults
DEBUG: bool = env.optional("DEBUG", default=False)
MAX_RETRIES: int = env.optional("MAX_RETRIES", default=3)
# Validated formats
EMAIL: str = env.require("ADMIN_EMAIL", format="email")
REDIS_URL: str = env.require("REDIS_URL", format="url")
# Now use them safely - guaranteed to be valid!
print(f"Connecting to {DATABASE_URL}")
Learn more in the Quick Start Guide →
Core Features
1. Import-Time Validation
Your app won't start with bad config.
from tripwire import env
# This line MUST succeed or ImportError is raised
API_KEY = env.require("API_KEY")
# No more runtime surprises!
2. Type Inference & Validation
Automatic type detection from annotations (v0.4.0+) - no need to specify type= twice!
from tripwire import env
# Type inferred from annotation
PORT: int = env.require("PORT", min_val=1, max_val=65535)
DEBUG: bool = env.optional("DEBUG", default=False)
TIMEOUT: float = env.optional("TIMEOUT", default=30.0)
# Lists and dicts
ALLOWED_HOSTS: list = env.require("ALLOWED_HOSTS") # Handles CSV or JSON
FEATURE_FLAGS: dict = env.optional("FEATURE_FLAGS", default={})
# Choices/enums
ENVIRONMENT: str = env.require("ENVIRONMENT", choices=["dev", "staging", "prod"])
Learn more about Type Inference →
3. Format Validators
Built-in validators for common formats.
# Email, URL, database, IP, UUID validation
ADMIN_EMAIL: str = env.require("ADMIN_EMAIL", format="email")
API_URL: str = env.require("API_URL", format="url")
DATABASE_URL: str = env.require("DATABASE_URL", format="postgresql")
SERVER_IP: str = env.require("SERVER_IP", format="ipv4")
# Custom regex patterns
API_KEY: str = env.require("API_KEY", pattern=r"^sk-[a-zA-Z0-9]{32}$")
4. Secret Detection & Git Audit
Detect secrets in .env and audit git history for leaks.
# Auto-detect and audit all secrets
$ tripwire audit --all
🔍 Auto-detecting secrets in .env file...
⚠️ Found 3 potential secret(s)
📊 Secret Leak Blast Radius
═══════════════════════════
🔍 Repository Secret Exposure
├─ 🔴 🚨 AWS_SECRET_ACCESS_KEY (47 occurrence(s))
│ ├─ Branches: origin/main, origin/develop
│ └─ Files: .env
├─ 🟡 ⚠️ STRIPE_SECRET_KEY (12 occurrence(s))
└─ 🟢 DATABASE_PASSWORD (0 occurrence(s))
📈 Summary: 2 leaked, 1 clean, 59 commits affected
Detects 45+ secret types: AWS, GitHub, Stripe, Azure, GCP, Slack, and more.
Learn more about Secret Management → | Git Audit Deep Dive →
Essential CLI Commands
# Initialize project
tripwire init
# Generate .env.example from code
tripwire generate
# Check for drift between .env and .env.example
tripwire check
# Sync .env with .env.example
tripwire sync
# Compare configurations (v0.4.0+)
tripwire diff .env .env.prod
# Scan for secrets
tripwire scan --strict
# Audit git history for secret leaks
tripwire audit --all
# Validate .env without running app
tripwire validate
Framework Integration
FastAPI
from fastapi import FastAPI
from tripwire import env
# Validate at import time
DATABASE_URL: str = env.require("DATABASE_URL", format="postgresql")
SECRET_KEY: str = env.require("SECRET_KEY", secret=True, min_length=32)
DEBUG: bool = env.optional("DEBUG", default=False)
app = FastAPI(debug=DEBUG)
@app.on_event("startup")
async def startup():
print(f"Connecting to {DATABASE_URL[:20]}...")
Django
# settings.py
from tripwire import env
SECRET_KEY = env.require("DJANGO_SECRET_KEY", secret=True, min_length=50)
DEBUG = env.optional("DEBUG", default=False)
ALLOWED_HOSTS = env.optional("ALLOWED_HOSTS", default=["localhost"], type=list)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': env.require("DB_NAME"),
'USER': env.require("DB_USER"),
'PASSWORD': env.require("DB_PASSWORD", secret=True),
'HOST': env.optional("DB_HOST", default="localhost"),
'PORT': env.optional("DB_PORT", default=5432),
}
}
Flask
from flask import Flask
from tripwire import env
# Validate before app creation
DATABASE_URL: str = env.require("DATABASE_URL", format="postgresql")
SECRET_KEY: str = env.require("SECRET_KEY", secret=True)
DEBUG: bool = env.optional("DEBUG", default=False)
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DATABASE_URL
app.config['SECRET_KEY'] = SECRET_KEY
Configuration as Code
Define environment variables declaratively using TOML schemas (v0.3.0+).
# .tripwire.toml
[project]
name = "my-app"
version = "1.0.0"
[variables.DATABASE_URL]
type = "string"
required = true
format = "postgresql"
description = "PostgreSQL connection"
secret = true
[variables.PORT]
type = "int"
required = false
default = 8000
min = 1024
max = 65535
[environments.production]
strict_secrets = true
# Validate against schema
tripwire schema validate --environment production
# Generate .env.example from schema
tripwire schema to-example
# Migrate legacy .env.example to schema (v0.4.1+)
tripwire schema from-example
Learn more about Configuration as Code →
CI/CD Integration
GitHub Actions
name: Validate Environment
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install tripwire-py
- run: tripwire generate --check
- run: tripwire scan --strict
- run: tripwire schema validate --strict
Comparison with Alternatives
| Feature | TripWire | python-decouple | environs | pydantic-settings | python-dotenv |
|---|---|---|---|---|---|
| Import-time validation | ✅ | ❌ | ⚠️ | ⚠️ | ❌ |
| Type coercion | ✅ | ⚠️ Basic | ✅ | ✅ | ❌ |
| Format validators | ✅ | ❌ | ✅ | ✅ | ❌ |
| .env.example generation | ✅ | ❌ | ❌ | ❌ | ❌ |
| Team sync (drift detection) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Secret detection (45+ patterns) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Git history auditing | ✅ | ❌ | ❌ | ❌ | ❌ |
| CLI tools | ✅ | ❌ | ❌ | ❌ | ⚠️ |
| Multi-environment | ✅ | ✅ | ✅ | ✅ | ✅ |
What Makes TripWire Different?
While all these libraries handle environment variables, TripWire focuses on the complete developer workflow:
- Prevent production failures with import-time validation
- Keep teams in sync with automated .env.example generation
- Protect secrets with detection and git history auditing
- Streamline onboarding with CLI tools for env management
TripWire is designed for teams that want comprehensive config management, not just loading .env files.
When to Choose Each Library
Choose TripWire When:
- You need guaranteed import-time validation to prevent production starts with invalid config
- Your team struggles with .env file drift and keeping documentation current
- Security is paramount and you need secret detection/git history auditing
- You want automated .env.example generation from your code
- You prefer comprehensive CLI tools for environment management
Choose python-dotenv When:
- You need a minimal, zero-config .env loader
- You're building a simple script or small project
- Minimal dependencies are a priority
Choose environs When:
- You need comprehensive type validation powered by marshmallow
- You're already using marshmallow in your project
Choose pydantic-settings When:
- Your project already uses Pydantic for data validation
- You need settings to integrate seamlessly with FastAPI
Choose python-decouple When:
- You want strict separation of config from code with minimal overhead
- You need zero dependencies
Acknowledgments
TripWire builds on the excellent work of the Python community, particularly:
- python-dotenv for reliable .env file parsing
- The validation patterns pioneered by environs and pydantic
- The config separation philosophy of python-decouple
Development Roadmap
Implemented Features ✅
- Environment variable loading
- Import-time validation
- Type coercion (str, int, bool, float, list, dict)
- Type inference from annotations (v0.4.0)
- Format validators (email, url, uuid, ipv4, postgresql)
- Custom validators
- .env.example generation from code
- Drift detection and team sync
- Configuration comparison (diff command - v0.4.0)
- Multi-environment support
- Unified config abstraction (.env + TOML - v0.4.0)
- Secret detection (45+ platform patterns)
- Git audit with timeline and remediation (audit command)
- Configuration as Code (TOML schemas - v0.3.0)
- Tool configuration (
[tool.tripwire]- v0.4.1) - Schema migration (schema from-example - v0.4.1)
Planned Features 📋
- VS Code extension (env var autocomplete)
- PyCharm plugin
- Cloud secrets support (AWS Secrets Manager, Vault)
- Encrypted .env files
- Web UI for team env management
- Environment variable versioning
- Compliance reports (SOC2, HIPAA)
Documentation
Complete documentation is available at docs/README.md:
Getting Started
Guides
- CLI Reference
- Configuration as Code
- Secret Management
- Framework Integration
- Multi-Environment
- CI/CD Integration
Reference
Advanced
Contributing
We welcome contributions! See our development workflow:
# Clone and setup
git clone https://github.com/Daily-Nerd/TripWire.git
cd tripwire
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e ".[dev]"
# Run tests
pytest
# Run linter
ruff check .
# Format code
black .
See CONTRIBUTING.md for detailed guidelines.
License
MIT License - see LICENSE file for details.
Support
- GitHub: github.com/Daily-Nerd/TripWire
- Issues: github.com/Daily-Nerd/TripWire/issues
- PyPI: pypi.org/project/tripwire-py
TripWire - Environment variables that just work. 🎯
Stop debugging production crashes. Start shipping with confidence.
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 tripwire_py-0.5.2.tar.gz.
File metadata
- Download URL: tripwire_py-0.5.2.tar.gz
- Upload date:
- Size: 344.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8cbc48a808006e7af197cac3a5bb8e3b2bf8194e7b0f51a9b3348733b5baa83
|
|
| MD5 |
6d12021431efab0742dab82aab30ea9b
|
|
| BLAKE2b-256 |
1a12ab0f13cb72e117f2b92d91f862298549c8d8d9a7ae4fb5aa0bade0756609
|
Provenance
The following attestation bundles were made for tripwire_py-0.5.2.tar.gz:
Publisher:
release.yml on Daily-Nerd/TripWire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tripwire_py-0.5.2.tar.gz -
Subject digest:
c8cbc48a808006e7af197cac3a5bb8e3b2bf8194e7b0f51a9b3348733b5baa83 - Sigstore transparency entry: 598499958
- Sigstore integration time:
-
Permalink:
Daily-Nerd/TripWire@e847a70b8b5e4cd1d32d7669c094ff304f93b9af -
Branch / Tag:
refs/tags/v0.5.2 - Owner: https://github.com/Daily-Nerd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e847a70b8b5e4cd1d32d7669c094ff304f93b9af -
Trigger Event:
push
-
Statement type:
File details
Details for the file tripwire_py-0.5.2-py3-none-any.whl.
File metadata
- Download URL: tripwire_py-0.5.2-py3-none-any.whl
- Upload date:
- Size: 100.2 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 |
daffced4bbe52020f80d2ce162f504143f6ff3164103476154402bd9db381594
|
|
| MD5 |
b5be280d549681d3ad7482eee197a332
|
|
| BLAKE2b-256 |
de9aa0efd7045440511be1097554eed26964cbaf25a012e372cd923d9b40987a
|
Provenance
The following attestation bundles were made for tripwire_py-0.5.2-py3-none-any.whl:
Publisher:
release.yml on Daily-Nerd/TripWire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tripwire_py-0.5.2-py3-none-any.whl -
Subject digest:
daffced4bbe52020f80d2ce162f504143f6ff3164103476154402bd9db381594 - Sigstore transparency entry: 598499963
- Sigstore integration time:
-
Permalink:
Daily-Nerd/TripWire@e847a70b8b5e4cd1d32d7669c094ff304f93b9af -
Branch / Tag:
refs/tags/v0.5.2 - Owner: https://github.com/Daily-Nerd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e847a70b8b5e4cd1d32d7669c094ff304f93b9af -
Trigger Event:
push
-
Statement type: