Skip to main content

A Python library for unified secrets management across HashiCorp Vault, system keyring, and .env files.

Project description

credential-bridge

A unified Python library for secrets management across HashiCorp Vault, the OS system keyring, and .env files.


Table of Contents


Features

  • Three backends: HashiCorp Vault (KV-v2), OS system keyring, and .env files
  • SecretsManager facade: switch backends without changing application code
  • Plugin architecture: register third-party backends with one call
  • Typed exceptions: granular hierarchy rooted at CredentialBridgeError
  • Typer + Rich CLI: cb, vault-cli, keyring-cli, env-cli, and run-wizard entry points
  • Cross-platform: works on Linux, macOS, and Windows

Installation

pip install credential-bridge

# With dev dependencies
pip install "credential-bridge[dev]"

Quick Start

Using SecretsManager

from credential_bridge import SecretsManager

# HashiCorp Vault (set VAULT_ADDR env var first)
sm = SecretsManager("vault", vault_token="s.xxx")
sm.add_secret("myapp/database", {"user": "admin", "pass": "s3cr3t"})
secret = sm.get_secret("myapp/database")

# System keyring
sm = SecretsManager("keyring", service_name="myapp")
sm.add_secret("api_key", {"api_key": "sk-abc123"})

# .env file
sm = SecretsManager("env", path=".env")
sm.add_secret("DATABASE", {"DB_HOST": "localhost", "DB_PORT": "5432"})

Using backends directly

from credential_bridge import VaultBackend, KeyringBackend, EnvFileBackend

# Vault with AppRole auth
vault = VaultBackend(
    vault_url="https://vault.example.com",
    vault_role_id="<role-id>",
    vault_secret_id="<secret-id>",
)
vault.add_secret("myapp/db", {"password": "hunter2"})

# Keyring
kr = KeyringBackend(service_name="myapp")
kr.add_secret("token", {"value": "sk-abc123"})

# .env file
env = EnvFileBackend(path=".env")
env.add_secret("DATABASE", {"DB_HOST": "localhost", "DB_PORT": "5432"})

CLI Usage

# Show all commands
cb --help

# Vault
cb vault add myapp/db --secret user=admin --secret pass=s3cr3t
cb vault get myapp/db
cb vault list
cb vault delete myapp/db

# Keyring
cb keyring add api_key --secret api_key=sk-abc123 --service-name myapp
cb keyring get api_key --service-name myapp
cb keyring delete api_key --service-name myapp

# .env file
cb env add DATABASE --secret DB_HOST=localhost --secret DB_PORT=5432
cb env get DB_HOST
cb env list
cb env delete DB_HOST

# Interactive wizard
cb wizard

Backends

Backend Best use case
Vault Production workloads requiring audit logs, dynamic secrets, fine-grained policies, and centralized governance
Keyring Developer machines and CI environments where OS-level credential storage is available
.env file Local development, Docker Compose setups, and twelve-factor apps that read config from the environment

Custom Backends

Implement BaseSecretBackend and register it with SecretsManager:

from credential_bridge import BaseSecretBackend, SecretsManager
from credential_bridge.manager import register_backend
from typing import Any, Dict, List

class RedisBackend(BaseSecretBackend):
    backend_name = "redis"  # required — omitting raises TypeError

    def add_secret(self, name: str, secret: Dict[str, Any]) -> None: ...
    def get_secret(self, name: str) -> Dict[str, Any]: ...
    def update_secret(self, name: str, secret: Dict[str, Any]) -> None: ...
    def delete_secret(self, name: str) -> None: ...
    def list_secrets(self, path: str = "") -> List[str]: ...

register_backend("redis", RedisBackend)

sm = SecretsManager("redis", host="localhost", port=6379)

Error Handling

All exceptions inherit from CredentialBridgeError:

CredentialBridgeError
├── BackendError
│   ├── VaultError
│   │   ├── VaultAuthError          — bad token / AppRole credentials
│   │   ├── VaultConnectionError    — unreachable server
│   │   └── VaultSecretNotFoundError — secret path does not exist
│   ├── KeyringError
│   └── EnvFileError
│       ├── EnvFileNotFoundError    — key not found
│       └── EnvFileKeyExistsError   — add_secret called on existing key
├── BackendNotRegisteredError
└── ConfigurationError
from credential_bridge import (
    SecretsManager,
    VaultAuthError,
    VaultConnectionError,
    VaultSecretNotFoundError,
    CredentialBridgeError,
)

sm = SecretsManager("vault", vault_token="s.xxx")

try:
    secret = sm.get_secret("myapp/database")
except VaultSecretNotFoundError:
    print("Secret path does not exist")
except VaultAuthError:
    print("Authentication failed — check your token or AppRole credentials")
except VaultConnectionError:
    print("Could not reach Vault — check VAULT_ADDR")
except CredentialBridgeError as exc:
    print(f"Unexpected error: {exc}")

Environment Variables

Variable Description
VAULT_ADDR Vault server URL (e.g. https://vault.example.com)
VAULT_TOKEN Token for Token auth method
VAULT_ROLE_ID Role ID for AppRole auth method
VAULT_SECRET_ID Secret ID for AppRole auth method

Resolution order for VaultBackend: constructor argument → environment variable → ~/.vault_config.json.


Development

# Install in editable mode with dev dependencies
pip install -e ".[dev]"

# Run unit tests
pytest tests/unit/

# Run integration tests (requires external services)
pytest tests/integration/ -m integration

# Lint
ruff check src/

# Type check
mypy src/

# Serve docs locally
mkdocs serve

CI Pipeline

Every push to main and every pull request runs automatically via shared-workflows:

Job What it checks
Test pytest on Python 3.8 / 3.10 / 3.12 x Ubuntu + Windows (runs after lint and typecheck pass)
Lint ruff check + ruff format --check
Type Check mypy src/
Audit pip-audit — all dependencies scanned for known CVEs
Coverage pytest-cov — report posted to the Actions job summary

Contributing

All contributions are welcome! Fork the repo, make your changes, and open a pull request. You can also open an issue with the label enhancement.

View all contributors


License

MIT — see LICENSE.txt for details.

(back to top)

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

credential_bridge-0.3.1.tar.gz (1.0 MB view details)

Uploaded Source

Built Distribution

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

credential_bridge-0.3.1-py3-none-any.whl (33.2 kB view details)

Uploaded Python 3

File details

Details for the file credential_bridge-0.3.1.tar.gz.

File metadata

  • Download URL: credential_bridge-0.3.1.tar.gz
  • Upload date:
  • Size: 1.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for credential_bridge-0.3.1.tar.gz
Algorithm Hash digest
SHA256 6d94fd83f63888ef1c2476b07518fc867bde2461f57862c5156c65993ce638df
MD5 b6d0c61e2d0b7fc716ce49ae039b9d30
BLAKE2b-256 336ef56d2947a4199c08e9cb77af84d71c36da84288f4e0443953374086c5a06

See more details on using hashes here.

File details

Details for the file credential_bridge-0.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for credential_bridge-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1be41679ce9c3ae9c68f61b6b29756f7e22250230e337667698a3e9e27931507
MD5 217c43d2e969bd2f37bd80f683d35d2a
BLAKE2b-256 fa7276decaecbe613391a4d9d905ce5417d6598dd1647a429930bca9a329e662

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