feat(secrets): pluggable SecretSource interface + multi-source orchestrator
Introduces a first-class secret-source contract so password managers (Bitwarden today, 1Password next, third-party vaults as plugins) plug into one orchestrated startup path instead of each hardcoding into env_loader. - agent/secret_sources/base.py: SecretSource ABC (fetch-only contract: never raises, never prompts, sync with orchestrator-enforced timeout), shared ErrorKind taxonomy, FetchResult, run_secret_cli() minimal-env subprocess helper, API versioning for plugin compatibility. - agent/secret_sources/registry.py: registration gating (name/scheme uniqueness, api_version, shape), apply_all() orchestrator owning precedence (mapped-beats-bulk, first-claim-wins, override_existing never crosses sources, protected bootstrap tokens), conflict warnings, per-var provenance, per-source wall-clock timeout. - Bitwarden converted to a registered BitwardenSource (bulk shape); behavior unchanged, apply_bitwarden_secrets kept as legacy shim. - env_loader._apply_external_secret_sources now drives the orchestrator; provenance labels resolve through registry (e.g. '(from 1Password)'). - PluginContext.register_secret_source() for external backends. - secrets.sources optional ordering key in DEFAULT_CONFIG + example. - tests/secret_sources/: 47 new tests incl. reusable conformance kit (SecretSourceConformance) that plugin authors run against their source.
This commit is contained in:
@@ -639,20 +639,23 @@ def test_env_loader_calls_bsm_when_enabled(tmp_path, monkeypatch):
|
||||
monkeypatch.delenv("MY_BSM_KEY", raising=False)
|
||||
|
||||
called = {"n": 0}
|
||||
def fake_apply(**kwargs):
|
||||
|
||||
def fake_fetch(**kwargs):
|
||||
called["n"] += 1
|
||||
assert kwargs["enabled"] is True
|
||||
assert kwargs["project_id"] == "proj-1"
|
||||
os.environ["MY_BSM_KEY"] = "from-bsm"
|
||||
return bw.FetchResult(
|
||||
secrets={"MY_BSM_KEY": "from-bsm"},
|
||||
applied=["MY_BSM_KEY"],
|
||||
)
|
||||
return {"MY_BSM_KEY": "from-bsm"}, []
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agent.secret_sources.bitwarden.apply_bitwarden_secrets",
|
||||
fake_apply,
|
||||
"agent.secret_sources.bitwarden.find_bws",
|
||||
lambda **_kw: Path("/fake/bws"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"agent.secret_sources.bitwarden.fetch_bitwarden_secrets",
|
||||
fake_fetch,
|
||||
)
|
||||
from agent.secret_sources import registry as reg_module
|
||||
|
||||
reg_module._reset_registry_for_tests()
|
||||
|
||||
from hermes_cli.env_loader import _apply_external_secret_sources
|
||||
_apply_external_secret_sources(home)
|
||||
|
||||
Reference in New Issue
Block a user