Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…horization [SAO-17522] The authorization dependency builds its context before FastAPI binds and validates RuntimeTokenExchangeRequest. The context builder used body.get(...), so a request could reach the authorization provider with missing, null, empty, or wrongly typed target fields, and the resulting upstream 4xx surfaced to the caller as a 502 instead of a local validation error. Validate the body is a JSON object and that target_type and target_id are non-empty strings before authorization runs. Report failures as field-level ValidationErrorItem entries whose codes and messages match what Pydantic v2 emits for the same failures, so a rejection from the context builder is indistinguishable to a client from one by the endpoint's own body model, and without echoing the invalid values back. The OSS contract is unchanged: both fields stay opaque, with no validation for Orbit-specific values such as target_type="log_stream" or a UUID-shaped target_id. Unrelated body validation, including extra="forbid", stays in the Pydantic model, so an unknown field still reaches authorization first and is then rejected by the model.
josjeon
force-pushed
the
fix/sao-17418-runtime-token-auth
branch
from
September 24, 2026 19:42
53278bd to
4f25db6
Compare
13 tasks
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.
Summary
This PR hardens
POST /api/v1/auth/runtime-token-exchangeso malformed target context is rejected by Agent Control with a local422before any authorization provider is called.It preserves the OSS contract:
target_typeandtarget_idare required, non-empty strings, but their values remain opaque. Agent Control does not enforce Orbit-specific values such astarget_type="log_stream"or a UUID-shapedtarget_id.What happened
In the multitenant environment, runtime-token exchange intermittently returned
502. Agent Control logs showed the upstream authorization service returning422forruntime.token_exchange. The same incident window also contained upstream422responses forcontrol_bindings.read.The exact rejected runtime-token payload was not captured, so this PR does not claim that missing target fields were the confirmed production root cause.
Code inspection did identify a concrete boundary problem: the authorization dependency builds its context before FastAPI binds and validates
RuntimeTokenExchangeRequest. The previous context builder usedbody.get(...), so malformed requests could reach the provider with missing,null, empty, or incorrectly typed target fields. An upstream4xxis then exposed by Agent Control as502, rather than returning a useful local validation error.Goal
422for malformed runtime-token requests.log_streamor UUID validation to the OSS service.What changed
target_type: required, string, non-empty;target_id: required, string, non-empty.ValidationErrorItementries whose codes and messages match Pydantic v2 (missing,string_type, andstring_too_short).extra="forbid", in the existing Pydantic request model.422; authorization provider is not callednull, empty, or non-string target field422; authorization provider is not called422Scope
server/src/agent_control_server/endpoints/auth.pyserver/tests/test_runtime_token_exchange_endpoint.py422instead of reaching the upstream provider and potentially surfacing as502.Out of scope for this PR:
control_bindingsor attachment context builders.4xxlogging or diagnostic parsing. Tracked separately in SAO-17523, which touchesauth_framework/providers/http_upstream.pyand proceeds in parallel.422.log_streamplus a log-stream UUID; Agent Control intentionally does not duplicate that validation.Risk and Rollout
Testing
26 passed.100%.ci,validate,sdk-ts-ci,ui-ci,build-and-push-server, andcodecov/patch.make checksuites locally against the rebased tree: server tests912 passed,make lintclean across models/server/sdk, andmypy server/srcclean (51 files). Noteserver/MakefilepinsAGENT_CONTROL_DB_PORT=5432inTEST_DB_ENV, so the port must be overridden when another Postgres holds 5432.make typecheckreports 3 pre-existingopentelemetry.sdk.traceimport errors insdks/python, unrelated to this change and also present onmain.docker-publish.ymlonly pushes images onmainor av*tag (push: github.event_name != 'pull_request'), so there is no deployable image until this merges. Tracked under the parent story.Checklist
control_bindings.readare not changed here.AI Tool Assistance Usage Statement