Skip to content

feat: switch ProcessHookEvent from unary to bidi streaming for server-side policy decisions #31

@tumberger

Description

@tumberger

Problem

The sidecar currently always returns Allowed: true synchronously to the hook handler, then fires off the ProcessHookEvent unary RPC asynchronously. The backend's Decision enum (ALLOW, DENY, ASK) is unused infrastructure — there's no path for the backend to actually deny a tool call.

This is because ProcessHookEvent is a unary RPC. The sidecar would have to block on the RPC round-trip for every tool call to get a decision, which adds latency to every agent action.

Proposed solution

Switch ProcessHookEvent back to bidirectional streaming. The sidecar opens a persistent stream at session start and:

  1. Sends each hook event as a message on the stream
  2. Receives the policy decision (allow/deny/ask) back on the same stream
  3. Returns the decision to the hook handler synchronously

This gives the backend a real enforcement path while keeping latency low (no connection setup per event — the stream is already open).

Changes required

  • Proto (kontext-dev/proto): Change ProcessHookEvent from rpc ProcessHookEvent(ProcessHookEventRequest) returns (ProcessHookEventResponse) to rpc ProcessHookEvent(stream ProcessHookEventRequest) returns (stream ProcessHookEventResponse)
  • CLI sidecar: Open stream on session start, multiplex events onto it, wait for decisions before returning to hook handler
  • CLI backend client: Replace IngestEvent unary call with stream send/receive
  • API handler: Update ConnectRPC handler from unary to bidi streaming, evaluate policy per event, return decisions on the stream

Design considerations

  • Need a correlation ID per event so the sidecar can match responses to requests on the multiplexed stream
  • Fallback behavior when stream disconnects: fail-open (allow) or fail-closed (deny)? Configurable?
  • Latency budget: hook handlers need to respond in ~5-10ms. If the backend can't decide in time, should the sidecar fall back to a local decision?
  • This pairs with future Cedar policy evaluation (Agent credential isolation: tokens accessible via env vars bypass tool-level policy enforcement #1) — local Cedar for fast decisions, server-side for complex/org-wide policy

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions