agent-credential-broker: fork of vaultwarden-agent-broker + OpenBao backend

Mechanical rename (package agent_credential_broker; entry points
agent-broker{,-mcp,-plugin}; env AGENT_BROKER_*; paths agent-broker;
agent-browser credential provider 'broker'; MCP server name agent-broker).

New backend 'openbao': stdlib-only HTTP client for OpenBao/Vault KV v2
(approle login or token file/env; metadata-only ref index; lazy re-login
on 401/403; token renewal). bitwarden-cli backend kept as transition.
This commit is contained in:
me committed 2026-10-14 13:27:33 -06:00
commit be87900794
35 files changed
+5003

No files matched your search

+76
View File
@@ -0,0 +1,76 @@
"""Stable machine-readable error codes returned by the broker.
Every failure crosses the socket/MCP boundary as {code, message} only --
never with credential material attached.
"""
class BrokerError(Exception):
"""Error that is safe to surface to the agent (no secret material)."""
def __init__(self, code, message):
super().__init__(message)
self.code = code
self.message = message
def to_dict(self):
return {"code": self.code, "message": self.message}
def locked():
return BrokerError("BROKER_LOCKED", "broker is locked; run 'agent-broker unlock'")
def unconfigured(detail="missing API client credentials"):
return BrokerError(
"UNCONFIGURED",
f"broker not configured: {detail}",
)
def not_found(ref):
return BrokerError("NOT_FOUND", f"no credential with ref {ref!r}")
def ambiguous(ref, count):
return BrokerError("AMBIGUOUS_REF", f"ref {ref!r} matches {count} items; fix agent.ref duplicates")
def adapter_denied(ref, adapter):
return BrokerError("ADAPTER_DENIED", f"credential {ref!r} is not allowed for adapter {adapter!r}")
def origin_denied(ref, target):
return BrokerError("ORIGIN_DENIED", f"credential {ref!r} is not authorized for target {target!r}")
def denied(message):
return BrokerError("DENIED", message)
def invalid_argument(message):
return BrokerError("DENIED_INVALID_ARGUMENT", message)
def confirmation_required(ticket=None):
err = BrokerError("CONFIRMATION_REQUIRED", "operation requires interactive confirmation")
err.ticket = ticket
return err
def unsafe_tool_integration(tool):
return BrokerError(
"UNSAFE_TOOL_INTEGRATION",
f"{tool}: no credential-provider or safe injection path exists; refusing integration",
)
def backend_error(message):
"""Vault backend failure (e.g. `bw` subprocess). Never silently
falls back to another backend."""
return BrokerError("VAULT_BACKEND_ERROR", message)
def internal(message):
"""Server-side fault. Message must already be secret-free."""
return BrokerError("INTERNAL_ERROR", message)