feat(agentex): forward user api key to agent pods via acp headers#245
Open
cdvillegas wants to merge 8 commits into
Open
feat(agentex): forward user api key to agent pods via acp headers#245cdvillegas wants to merge 8 commits into
cdvillegas wants to merge 8 commits into
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
…merge style Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…aders Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
danielmillerp
approved these changes
May 21, 2026
Collaborator
danielmillerp
left a comment
There was a problem hiding this comment.
looks good thanks for fast PR here!!
|
|
||
| from typing import Any | ||
|
|
||
| HEADER_ACTING_AS_AGENT = "x-acting-as-agent" |
Collaborator
There was a problem hiding this comment.
can you add a comment explaining why we are doing this? on first reading it feels weird to send the agent id to the agent haha
Author
There was a problem hiding this comment.
On second thought idk if we need this header (ticket called for it). Eventually agents will be Hydra clients minting OBO tokens with agent id in the claim, so sending it separately as a header feels redundant. I went ahead and removed it.
Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request Summary
Runtime delegation v1 plumbing: when a user calls scale-agentex with
x-api-keyand auth succeeds, outbound ACP JSON-RPC calls to agent pods includex-acting-user-api-key(from the inbound request),x-acting-as-agent, and optionalx-selected-account-id. Clients cannot spoof the acting headers; they are blocked on ingress and set only server-side.No agentex-auth changes: validation still uses
/v1/authn; the user key is not stored onprincipal_context. Agent pods must readx-acting-user-api-keyand pass it to SGP (SDKPassthroughResolveris a follow-up).Test Plan
test_send_message_includes_delegation_headersasserting acting headers on ACPdefault_headers.AgentACPServiceunit/use-case fixtures to inject a mockRequestwithprincipal_contextand headers.Linear Issue
Resolves AGX1-240
Made with Cursor
Greptile Summary
This PR wires up runtime-delegation v1: when a user authenticates with
x-api-key, every outbound ACP JSON-RPC call to agent pods now carriesx-acting-user-api-key(and optionallyx-selected-account-id) so agents can call downstream services as the user. Client spoofing is prevented by addingx-api-keyand thex-acting-*headers toBLOCKED_HEADERS, and delegation is only emitted when auth has already validated a non-agent principal.delegation_headers.pyencapsulates the logic;AgentACPServiceis injected with the FastAPIRequestto readprincipal_contextand inbound headers, andget_headersis unified to merge filtered passthrough → delegation → agent-auth → serverx-request-id(last wins).request_utils.pyextends the log-scrubbing blacklist withapi-keyandacting-userpatterns;middleware_utils.pyreplaces fullprincipal_contextobject logging with scopeduser_id/account_idfields to limit sensitive data exposure in logs.x-api-keypassthrough, and server-sidex-request-idoverride.Confidence Score: 4/5
Safe to merge with one known open security item: x-selected-account-id is absent from BLOCKED_HEADERS, so an authenticated caller can supply their own account ID on the send_event path and have it forwarded to agent pods.
The delegation header plumbing is well-constructed — x-api-key and x-acting-* are properly blocked, x-request-id is server-generated last so it cannot be overridden, and the principal guard in build_delegation_headers ensures keys are only forwarded for authenticated user requests. The one unresolved gap is x-selected-account-id missing from BLOCKED_HEADERS: when delegation does not fire, a client-supplied x-selected-account-id passes through filter_request_headers into the outbound ACP call, contradicting the PR's stated invariant that acting headers are set only server-side.
agentex/src/domain/services/agent_acp_service.py — BLOCKED_HEADERS needs x-selected-account-id added to close the acting-header spoofing gap on the send_event path.
Important Files Changed
Comments Outside Diff (2)
agentex/src/domain/services/agent_acp_service.py, line 83-110 (link)x-api-keymissing fromBLOCKED_HEADERS, leaking raw key alongside delegation headerFor the
EVENT_SENDpath, the route handler passesdict(fastapi_request.headers)(all inbound headers) asrequest_headers. Sincex-api-keyis not inBLOCKED_HEADERS,filter_request_headerslets it through, so agent pods receive the user's raw API key asx-api-keyin addition to the properly-gatedx-acting-user-api-key. The PR's stated goal is controlled key forwarding through delegation; this gap means the key is also forwarded verbatim, bypassing that control for everysend_eventcall made by a user principal. Adding"x-api-key"toBLOCKED_HEADERSwould close this.Prompt To Fix With AI
agentex/src/domain/services/agent_acp_service.py, line 72-81 (link)x-selected-account-idmissing fromBLOCKED_HEADERSThe PR blocks
x-acting-user-api-keyandx-acting-as-agentbut omitsx-selected-account-id. Forsend_eventcalls,request_headersis the full inbound client header map passed throughfilter_request_headers. When delegation doesn't fire (e.g., the user authenticates via a non-x-api-keymechanism sobuild_delegation_headersreturns{}), the client-suppliedx-selected-account-idpasses throughfiltered_request_headersand is forwarded verbatim to the agent pod. This lets an authenticated caller pick an arbitrary account ID for downstream SGP operations — contradicting the PR's stated invariant that acting headers "are blocked on ingress and set only server-side." Adding"x-selected-account-id"toBLOCKED_HEADERScloses this gap.Prompt To Fix With AI
Reviews (4): Last reviewed commit: "refactor(agentex): drop x-acting-as-agen..." | Re-trigger Greptile