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:
commit
be87900794
35 files changed
+5003
No files matched your search
@@ -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)
|
||||
Reference in new issue
Block a user