fix: harden Bitwarden profile secret loading - #50686
Conversation
Add Bitwarden key_prefix/strip_prefix runtime mapping so shared Secrets Manager projects can safely load only profile-scoped env vars, update CLI/status/sync/docs, and cover the behavior with hermetic tests.\n\nAlso resolves closeout blockers by including the prepared Discord voice receiver chunking config and reusable noise-gate contract test suite so the working tree is no longer half-applied.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the profile-scoped secret work. The capability is still absent on current main, but this branch needs a focused salvage onto the current secret-source architecture.
Problems
hermes_cli/env_loader.py:341-346now callsregistry.apply_all(), andBitwardenSource.fetch()returns raw secret names atagent/secret_sources/bitwarden.py:642-697. The mapping added atagent/secret_sources/bitwarden.py:690is inside the legacy direct-apply path, so it is bypassed during normal startup on current main.- The Bitwarden change is bundled with channel routing, Discord voice chunking, and a noise-gate contract suite. These are independently risky surfaces and obscure review of the secret-loading behavior.
Suggested changes
- Move mapping into
BitwardenSource.fetch()beforeregistry.apply_all()consumesresult.secrets, and test the actual registry/env-loader path. - Split unrelated gateway, Discord, and contract-suite work. The linked #55886 identifies a competing mapping layer; choose one design before adding overlapping configuration.
Automated hermes-sweeper review.
| result.error = str(exc) | ||
| return result | ||
|
|
||
| secrets, mapping_warnings = map_secrets_for_env( |
There was a problem hiding this comment.
Current main no longer calls apply_bitwarden_secrets() from startup: hermes_cli/env_loader.py delegates to registry.apply_all(), which uses BitwardenSource.fetch(). Apply this mapping in BitwardenSource.fetch() before it returns result.secrets, otherwise key_prefix and strip_prefix are bypassed at runtime.
|
Closing as superseded by #69058, which landed profile-scoped secret handling at the apply_all() orchestrator (suffix aliasing + preserve_existing) so every secret source — Bitwarden, 1Password, plugins — inherits it, rather than per-source config in the Bitwarden backend. Your prefix-mapping design solved the same shared-project problem and predates that direction; the writeups in your setup/status/sync wiring were genuinely useful when scoping the orchestrator version. If explicit prefix→name mapping is still needed beyond suffix aliasing (tracked in #63088), the right shape now is a small orchestrator-level key_map — happy to review a focused PR for that. Note the Discord voice/noise-gate work bundled here should be its own PR regardless. Thanks @vasiliyx! |
Summary
key_prefix/strip_prefixruntime mapping so shared projects can safely expose profile-scoped env varshermes secrets bitwarden setup/status/syncTest plan
uv run --extra dev --extra messaging --extra acp python -m pytest tests/test_bitwarden_secrets.py tests/hermes_cli/test_secrets_bitwarden_non_tty.py tests/gateway/test_voice_command.py tests/contracts/test_noise_gate_contract.py -o 'addopts=' -q→237 passed, 11 skippeduv run --extra dev python -m ruff check agent/secret_sources/bitwarden.py hermes_cli/env_loader.py hermes_cli/secrets_cli.py hermes_cli/config.py tests/test_bitwarden_secrets.py plugins/platforms/discord/adapter.py tests/gateway/test_voice_command.py tests/contracts/test_noise_gate_contract.py→ passgit diff --check→ passhermes --profile critic ...) → PASSNotes
A broader local
pytest tests/ -qattempt was not a useful signal in this macOS profile: collection/run hit unrelated environment/resource issues (missing optional extras on the first attempt, then long-running suite timeout/open-file pressure after installing optional extras). Targeted changed-area tests and critic review passed.