fix(gateway): require agent-issued approval identities

This commit is contained in:
Rod Boev 2026-07-19 15:58:37 -04:00
parent a91bd88c70
commit fb88095530
2 changed files with 54 additions and 1 deletions

View file

@ -506,7 +506,7 @@ def _run_gateway_runs_api_streaming(
if approval_data:
approval_data["run_id"] = run_id
from api.config import gateway_supports_approval_identity_v1
approval_data["_gateway_agent_identity_v1"] = gateway_supports_approval_identity_v1(base_url, api_key)
approval_data["_gateway_agent_identity_v1"] = bool(approval_data.get("approval_id")) and gateway_supports_approval_identity_v1(base_url, api_key)
from api.route_approvals import submit_gateway_pending_mirror
head, total = submit_gateway_pending_mirror(session_id, approval_data)
put_gateway_event("approval", {**(head or approval_data), "pending_count": total})

View file

@ -2158,6 +2158,59 @@ def test_synthetic_gateway_identity_stays_fifo_after_capability_upgrade():
approvals._pending.pop("sess-upgrade", None)
def test_agent_identity_v1_relays_the_ingress_identity_exactly():
"""An Agent-issued v1 identity is the only targeted relay authority."""
from api import routes
from api.gateway_chat import _STREAM_RUN_IDS
import api.route_approvals as approvals
_STREAM_RUN_IDS["sid-v1"] = "run-v1"
approvals.submit_gateway_pending_mirror("sess-v1", {
"run_id": "run-v1", "approval_id": "agent-v1", "command": "echo x",
"_gateway_agent_identity_v1": True,
})
mirror = approvals.gateway_pending_mirror("sess-v1", approval_id="agent-v1", run_id="run-v1")
assert mirror["_gateway_agent_identity_v1"] is True
handler = MagicMock()
handler.wfile = io.BytesIO()
with patch("api.routes.get_session", return_value=SimpleNamespace(active_stream_id="sid-v1")), \
patch("api.config.gateway_supports_approval_identity_v1", return_value=True), \
patch("api.runner_client.HttpRunnerClient.respond_approval") as respond:
routes._handle_approval_respond(handler, {
"session_id": "sess-v1", "choice": "once", "approval_id": "agent-v1",
})
respond.assert_called_once_with("run-v1", "agent-v1", "once")
_STREAM_RUN_IDS.pop("sid-v1", None)
approvals._pending.pop("sess-v1", None)
def test_capability_v1_empty_ingress_identity_stays_fifo_only():
"""Capability alone cannot promote a locally synthesized gwrun identity."""
from api import routes
from api.gateway_chat import _STREAM_RUN_IDS
import api.route_approvals as approvals
_STREAM_RUN_IDS["sid-v1-empty"] = "run-v1-empty"
approvals.submit_gateway_pending_mirror("sess-v1-empty", {
"run_id": "run-v1-empty", "approval_id": "", "command": "echo x",
"_gateway_agent_identity_v1": False,
})
mirror = approvals.gateway_pending_mirror("sess-v1-empty", run_id="run-v1-empty")
assert mirror["approval_id"].startswith("gwrun:run-v1-empty:")
assert mirror["_gateway_agent_identity_v1"] is False
handler = MagicMock()
handler.wfile = io.BytesIO()
with patch("api.routes.get_session", return_value=SimpleNamespace(active_stream_id="sid-v1-empty")), \
patch("api.config.gateway_supports_approval_identity_v1", return_value=True), \
patch("api.runner_client.HttpRunnerClient.respond_approval") as respond:
routes._handle_approval_respond(handler, {
"session_id": "sess-v1-empty", "choice": "once", "approval_id": mirror["approval_id"],
})
respond.assert_called_once_with("run-v1-empty", "", "once")
_STREAM_RUN_IDS.pop("sid-v1-empty", None)
approvals._pending.pop("sess-v1-empty", None)
def test_gateway_approval_response_without_approval_id_409s():
"""Gateway relay requires the emitted per-approval id, not bare run state."""
from api.gateway_chat import _STREAM_RUN_IDS