Metadata-Version: 2.4
Name: harbinger_vault_client
Version: 0.3.0
Summary: Thin Python client for the Harbinger credential service
Author: Moises Gaspar
Author-email: moises.gaspar@testsieger.com
License: MIT
Keywords: vault,credentials,client,retry,connection-pooling,rate-limiting,enterprise
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Security
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests<3,>=2.25.1
Requires-Dist: urllib3<3,>=1.26.0
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Provides-Extra: test
Requires-Dist: pytest>=6.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# Changelog

All notable changes to this project will be documented in this file.

## [0.3.0] - 2026-05-15

### Breaking changes
- **Errors are now raised as typed exceptions**, not returned as `{"error": {...}}` dicts.
  Every exception subclasses `VaultError` and carries an RFC 9457 `Problem` instance on
  `.problem` (verbatim server body preserved on `.problem.response_body`).
- `ContainerNameError` is now raised from `__init__` instead of being stored on `self.error`.
  The `self.error` attribute has been removed.
- `get_credentials` validates input: a bare string raises `TypeError`; an empty list
  raises `ValueError`.
- **Partial success behavior preserved by default**: the client returns whatever
  keys the server returned (same as v0.2.0), so callers that pre-fetch a fixed
  list of keys keep working. Pass `strict=True` on the constructor to opt into
  raising `CredentialNotFoundError` when any requested key is absent (and
  `CredentialCorruptedError` when the new envelope reports corruption).
- Python floor raised to `>=3.10`.

### Migration

```python
# Before (v0.2.0) — still works against v0.3.0 with no changes:
result = client.get_credentials(["mysql_prod_rw"])
if "error" in result:           # legacy guard; v0.3.0 raises instead, so this is dead code
    log.error(result["error"])  #   but the next line still works on the happy path:
else:
    use(result["mysql_prod_rw"])

# After (v0.3.0) — recommended for new code:
from harbinger_vault_client import VaultError, CredentialNotFoundError
try:
    result = client.get_credentials(["mysql_prod_rw"])
    use(result["mysql_prod_rw"])
except VaultError as e:
    log.error("%s (status=%s): %s", type(e).__name__, e.status, e)

# Opt into strict mode if you want missing-key detection as an exception:
client = VaultClient(url, token, strict=True)
try:
    result = client.get_credentials(["mysql_prod_rw", "other_key"])
except CredentialNotFoundError as e:
    log.error("missing keys: %s, got: %s", e.missing, list(e.found))
```

### Deprecated (still functional, emit `DeprecationWarning`)
- Constructor kwargs honored but mapped: `retries_total` → `retries`,
  `retries_backoff_factor` → `backoff_factor`.
- Constructor kwargs ignored: `retries_statuses`, `pool_connections`, `pool_maxsize`,
  `pool_block`, `max_in_flight`, `rate_limit_per_sec`, `rate_limit_burst`,
  `use_idempotency_key`, `idempotency_namespace`.
- `set_extra_headers(...)` still works; prefer passing a pre-built `requests.Session`.

### Removed (no replacement)
- `_TokenBucket` rate limiter and `BoundedSemaphore` concurrency cap — silent blocking
  with no observability, redundant for a thin in-process client.
- `Idempotency-Key` header — confirmed unused by the server.
- 200/200 connection pool defaults — use library defaults.

### Retry behavior
- Total retries reduced from 6 → 3; backoff factor 1.5 → 0.5; max backoff 30s → 10s.
- `status_forcelist` is now `[502, 503, 504]` only. **401 is no longer retried** (bad
  tokens fail fast). 429 is not retried (unreachable in practice for in-cluster callers).
- Retries that did fire are logged at `WARNING`.

### Notable server-side facts that shape this client (per Harbinger team, 2026-05-15)
- "Credential not found" arrives as **HTTP 200 with the key absent** from the response
  when talking to legacy Harbinger; on the new additive envelope surface it appears in
  the response's `missing[]` list (see "Forward compatibility" below).
- Server-side decryption failures are indistinguishable from "missing" against legacy
  Harbinger. The new envelope surface separates them into `errors[]`.
- Server emits no request-id / correlation-id header on legacy. The new surface emits
  `X-Request-Id` on every response; this client extracts it onto `Problem.request_id`
  when present.
- Server does not read `Idempotency-Key`. The credential lookup is a read-only SELECT and
  is safe to retry blindly.

### SSL verification toggle
- New `verify` constructor kwarg, default `True`. Maps directly to
  `requests.Session.verify`: pass `verify=False` for self-signed certificates on
  internal HTTPS endpoints, or pass a path string to use a custom CA bundle.
  When a caller supplies their own `session`, its existing `verify` setting is
  respected (the kwarg is ignored for that case).

### Forward compatibility with the upcoming additive Harbinger surface (2026-05+)
Harbinger is adding three purely additive features that this client opportunistically
consumes. **Old Harbinger versions remain fully supported** — every new behavior
activates only when the server actually provides it.

- **`meta: true` request field** — sent by default. Old Harbinger versions ignore unknown
  msgspec fields; new versions interpret it and return the envelope shape below. Pass
  `meta=False` to the constructor to force legacy mode.
- **Envelope response shape** — `{"credentials": {...}, "missing": [...], "errors": [...],
  "types": {...}}`. Detected automatically by checking whether `body["credentials"]` is
  a dict. When detected, `missing` / `errors` come from the server; against legacy
  servers we keep diffing requested vs returned keys (and `errors` stays empty).
- **`CredentialCorruptedError`** — new exception, raised when the envelope's `errors[]`
  is non-empty. Subclass of `CredentialNotFoundError`, so existing handlers keep working.
- **`code` field on error bodies** — when present, promoted to `Problem.type`. Stable
  vocabulary: `auth_invalid_token`, `auth_required`, `auth_bearer_required`,
  `auth_container_mismatch`, `auth_missing_scope`. Callers can dispatch on
  `exc.code == "auth_invalid_token"` rather than substring-matching the message.
- **`X-Request-Id` response header** — when present, exposed on `Problem.request_id`
  and logged at DEBUG. Useful for cross-referencing client logs with Harbinger logs.

## [0.2.0] - 2024-12-28

### 🚀 Major Release: Enhanced Vault Client with Enterprise-Grade Reliability

### 🔧 Critical Fixes
- **FIXED: Eliminated 401 auth failures under concurrent load** - The primary issue resolved
- **FIXED: Removed `raise_for_status()` that was killing retry mechanism** - Critical bug fix
- **FIXED: Transient connection failures now automatically retry** - No more denied services

### 🎯 Core Enhancements
- **Enhanced retry mechanism** with exponential backoff (6 retries, 1.5x backoff factor)
- **Automatic retry on 401 errors** - Handles server overload gracefully  
- **Connection pooling** for reduced server load and improved performance
- **Rate limiting by default** (15 req/sec, 10 burst) to prevent server overload
- **Concurrency control** (30 max concurrent) to prevent overwhelming vault server
- **Idempotency keys** for safe retry operations using UUID5
- **Enhanced error handling** with detailed timeout and network error codes

### 📊 Performance Improvements  
- **Session reuse** - HTTP connections are pooled and reused
- **Reduced server load** - Connection pooling + rate limiting + concurrency control
- **Better backoff strategy** - Exponential backoff gives server time to recover
- **Optimized defaults** - Tuned for production reliability

### 🛠️ New Configuration Options
- `retries_total` - Number of retry attempts (default: 6, was 0)
- `retries_backoff_factor` - Exponential backoff factor (default: 1.5)
- `max_in_flight` - Maximum concurrent requests (default: 30)
- `rate_limit_per_sec` - Rate limiting per second (default: 15.0, was None)
- `rate_limit_burst` - Burst capacity for rate limiting (default: 10)
- `pool_connections` - HTTP connection pool size (default: 50)
- `pool_maxsize` - Maximum pool size (default: 50)
- `use_idempotency_key` - Enable idempotency keys (default: True)
- `timeout` - Enhanced timeout handling (default: 10.0s)

### 📦 Dependencies
- Added `urllib3>=1.26.0,<3` for enhanced retry functionality with proper status code handling

### ✅ Backward Compatibility
- **100% backward compatibility** maintained and tested
- All existing APIs preserved exactly
- Error response format unchanged
- Environment variable handling unchanged
- Drop-in replacement for v0.1.0

### 📈 Proven Performance
- **Eliminated concurrent request failures** in load testing
- **Handles 600+ concurrent requests** across 20 vault keys
- **>95% success rate** under extreme load (200 threads, mixed client patterns)
- **Tested with realistic production patterns** (70% reused clients, 30% new instances)

### 🎯 Migration Notes
- **Zero code changes required** for existing implementations
- Enhanced reliability works automatically with new defaults
- Optional: Tune parameters for specific use cases
- **Recommended**: Update to v0.2.0 for production stability

### 🧪 Quality Assurance
- Comprehensive load testing with 1,280+ requests across all vault keys
- Tested single key contention, multi-key scenarios, and mixed client patterns
- JSON-formatted verbose logging for complete request/response tracking
- Verified credential structure integrity across all scenarios

## [0.1.0] - 2024-12-XX

### Initial Release
- Basic vault client functionality
- Simple HTTP requests with timeout
- Environment-based container configuration
- Basic error handling
