Skip to content

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 29 May 23:43
· 51 commits to main since this release

First public release.

The adapter refactor (originally proposed for v0.3.0 in docs/adapter-architecture.md) is bundled with composite secrets and shipped together as v0.4.0.

Added

  • Composite secret bindings (inject.template + compose:). Bindings can now assemble a credential from 1-4 atomic BWS values at fetch time, instead of requiring the operator to pre-concatenate values in BWS (which made single-key rotation silently stale). Templates use Jinja2 syntax evaluated through ImmutableSandboxedEnvironment with a strict filter/function whitelist (b64encode, b64decode, sha256, urlencode, hmac_sha256, hmac_sha512). An AST-level deny-by-default validator at config-load rejects every Jinja2 construct outside the small set the proxy supports, class-walk escapes, control flow, attribute traversal, subscript, arithmetic are all structurally impossible. See bindings.example.yaml for a Jira / Atlassian Cloud example and docs/architecture.md §4.2 for the reference table and architectural sketch.
  • CachingSecretsClient.composite_fetch(names): atomically fetches multiple secrets under a single generation snapshot; empty BWS values raise BackendUnavailableError (never compose partial credentials); flush during assembly raises _StaleAfterFlushError so the caller restarts.
  • Same-UUID heuristic: when two distinctly-named compose entries resolve to the same value (suggesting an operator typo pointing both names at one BWS secret), the addon logs a one-shot WARNING to its own logger. The warning never includes the actual secret value.
  • jinja2 >= 3.1 is now a declared direct dependency (previously transitive via mitmproxy).
  • SecretsBackend protocol + adapter architecture. bindings.yaml uses a discriminated backend: {type: bws, config: {...}} block. agent_vault_proxy.backends.bws.BitwardenBackend is the reference implementation; new backends (1Password Service Accounts, HashiCorp Vault, Doppler, etc.) plug in by registering a type discriminator. agent_vault_proxy.caching.CachingSecretsClient provides generic TTL+jitter+LRU+singleflight caching on top of any backend. Protocol design in docs/adapter-architecture.md.
  • mypy in CI + pre-commit. Strict-ish config (warn_return_any, warn_unused_ignores, no_implicit_optional, check_untyped_defs); third-party libs without stubs (mitmproxy, bitwarden_sdk, yaml) explicitly silenced.
  • Ruff C90 cyclomatic-complexity gate (max-complexity = 10). Three pre-existing functions carry # noqa: C901 with one-line provenance justifications.
  • Hash-pinned dev dependencies. requirements-dev.lock is now hash-pinned alongside requirements.lock. New helper scripts: scripts/check-lockfile-hashes.py (zero-dep structural check - every pinned package must carry a --hash=sha256: continuation) and scripts/check-lockfile-drift.sh (re-runs uv pip compile with the 7-day cooldown and diffs against committed). Both wired into pre-commit; the CI verify-lockfile job runs the same hash check before the drift diff.

Changed

  • Config: InjectSpec.format is now Optional[str] and a peer of the new InjectSpec.template: Optional[str]. Exactly one of the two must be set per binding (validator-enforced). Existing inject.format bindings continue to work unchanged.
  • Addon: request handlers now capture (config, client, audit) at handler entry, preventing a mid-request configure() reload from producing a torn state (Silas F3).
  • Dependency advances captured by the 7-day-cooldown regen: bitwarden-sdk 2.0.0 → 2.1.0, certifi 2026.4.22 → 2026.5.20, click 8.4.0 → 8.4.1, ruff 0.15.13 → 0.15.14.
  • Security CI stack refactored to drop GitHub Advanced Security dependency. CodeQL (Python SAST) replaced with Bandit + Semgrep (community rulesets: p/security-audit + p/python + p/secrets). Gitleaks (which required a paid license for org-owned repos as of Aug 2022) replaced with TruffleHog (AGPL-3, free for everyone). OSV-Scanner switched from the action wrapper to direct binary install (the wrapper passes scan-args as a single positional arg, breaking multi-flag invocation). All security jobs now gate the merge via job-fail instead of SARIF-upload to the Security tab, workflows portable to any git host, no GHAS settings to babysit. The same three Docker-based scanners (TruffleHog, OSV-Scanner, Semgrep) also run in pre-commit so most commits hit the same gates locally before push.

Removed

  • agent_vault_proxy.bws module (the BwsClient facade) and the top-level bws: config block deprecation shim in config.py. v0.4.0 is the first public release; there are no public v0.2.0 users to migrate. New bindings.yaml files must use the backend: {type: bws, config: {...}} form (shown in bindings.example.yaml).
  • CodeQL job from .github/workflows/security.yml (replaced by Bandit + Semgrep: see above).
  • Gitleaks pre-commit hook + CI job (replaced by TruffleHog - see above).