Overview
TheTrustBoundary enforces zero-trust isolation between agents. By default, all communication is denied unless explicitly allowed.
Deny-all by default
Controls
Global blocklist
Global blocklist
Block an agent from all communication:Blocking automatically removes the agent from the trusted list.
Global allowlist
Global allowlist
Trust an agent for all pairs:Trusting automatically removes the agent from the blocked list.
Scoped trust grants
Scoped trust grants
Restrict trust to specific receivers and payload types, and optionally set an expiry:A message from
analytics-agent is only permitted when the receiver matches allowed_receivers and the payload type matches allowed_payload_types. Any field left as None means “unrestricted for this dimension”. Once valid_until passes, the entry is treated as if it never existed and is auto-evicted on the next evaluation.Runtime revocation
Runtime revocation
Revoke a trust grant without restarting the service:Grants and revocations are written to the audit log with the redacted agent ID and
granted_by / revoked_by attribution. block_agent() also removes any existing trust entry as a side effect.Pair-level blocking
Pair-level blocking
Block a specific directional pair:
Scoped trust grants
trust_agent() accepts optional scope and expiry parameters so operators can grant narrow, time-bounded exceptions instead of permanent, unscoped bypasses.
evaluate() accepts an optional payload_type. When provided, it is checked against the allowed_payload_types field of both the sender entry (outbound filter) and the receiver entry (inbound filter) — the message is only trusted if the payload type is permitted by both sides:
Expired entries are treated as non-existent — including their scope. If you need permanent scope restrictions, leave
valid_until=None rather than setting a far-future expiry.evaluate(), so revocation via revoke_agent() or expiry via valid_until never requires a service restart.
Loading trust from environment
QWED_A2A_TRUSTED_AGENTS accepts two formats. The HTTP gateway calls load_from_env() on startup; both formats work interchangeably.
Simple CSV (unrestricted, no expiry):
agent_id; the other fields are optional. Invalid entries (non-object, missing ID, non-string scope values, non-finite valid_until) are logged and skipped without failing the load — the remaining entries still apply.
Token-bucket rate limiting
Rate limiting uses a token-bucket algorithm (not fixed-window), providing smooth, fair enforcement:Configuration
Automatic eviction
Cold pairs (no requests for 5 minutes) are automatically evicted from the rate-limit map to prevent unbounded memory growth. Eviction runs once per minute.Evaluation order
The trust boundary evaluates requests in this exact order:Steps 1–4 are stateless (no side effects). Rate-limit state is only allocated at step 5, after all policy checks pass.
Usage with the interceptor
The interceptor creates aTrustBoundary with default_allow=True by default, since it handles verification itself. For zero-trust deployments, inject your own: