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.2.6.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.2.6-py3-none-any.whl (30.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: credential_bridge-0.2.6.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.2.6.tar.gz
Algorithm Hash digest
SHA256 d0a57c4ea91865b1fca469b0a1ff3b1eabd854892de8a8ca9154a96220907039
MD5 a55a6e3028d481a2f8683179036e0b1c
BLAKE2b-256 b0a187802288d6be786b283e15510f3da80ad29d98a06bc13a828d85c1c2e7b0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for credential_bridge-0.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 44ff5f9dda5b5eb440b8ddee6f6ce80b61226e53c5ad321e6d8286ed00fdbf37
MD5 f0eac42333ac5d058e0cbb63a8192619
BLAKE2b-256 c8eb8b595c51c1fb154c5a37c6f555fc7acb4c0d9362f3609440d795afb9cac7

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