v0.4.0
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 throughImmutableSandboxedEnvironmentwith 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. Seebindings.example.yamlfor a Jira / Atlassian Cloud example anddocs/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 raiseBackendUnavailableError(never compose partial credentials); flush during assembly raises_StaleAfterFlushErrorso 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.1is now a declared direct dependency (previously transitive via mitmproxy).SecretsBackendprotocol + adapter architecture.bindings.yamluses a discriminatedbackend: {type: bws, config: {...}}block.agent_vault_proxy.backends.bws.BitwardenBackendis the reference implementation; new backends (1Password Service Accounts, HashiCorp Vault, Doppler, etc.) plug in by registering atypediscriminator.agent_vault_proxy.caching.CachingSecretsClientprovides generic TTL+jitter+LRU+singleflight caching on top of any backend. Protocol design indocs/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: C901with one-line provenance justifications. - Hash-pinned dev dependencies.
requirements-dev.lockis now hash-pinned alongsiderequirements.lock. New helper scripts:scripts/check-lockfile-hashes.py(zero-dep structural check - every pinned package must carry a--hash=sha256:continuation) andscripts/check-lockfile-drift.sh(re-runsuv pip compilewith the 7-day cooldown and diffs against committed). Both wired into pre-commit; the CIverify-lockfilejob runs the same hash check before the drift diff.
Changed
- Config:
InjectSpec.formatis nowOptional[str]and a peer of the newInjectSpec.template: Optional[str]. Exactly one of the two must be set per binding (validator-enforced). Existinginject.formatbindings continue to work unchanged. - Addon: request handlers now capture
(config, client, audit)at handler entry, preventing a mid-requestconfigure()reload from producing a torn state (Silas F3). - Dependency advances captured by the 7-day-cooldown regen:
bitwarden-sdk2.0.0 → 2.1.0,certifi2026.4.22 → 2026.5.20,click8.4.0 → 8.4.1,ruff0.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 passesscan-argsas 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.bwsmodule (theBwsClientfacade) and the top-levelbws:config block deprecation shim inconfig.py. v0.4.0 is the first public release; there are no public v0.2.0 users to migrate. Newbindings.yamlfiles must use thebackend: {type: bws, config: {...}}form (shown inbindings.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).