mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
The prior fix (6ed4e139) covered the flow/do MCP servers but missed four
other agent->orchestrator call sites that built the header dict by hand
and omitted X-Agent-Token and/or X-Agent-Team. With ROBOCO_AGENT_AUTH_REQUIRED
armed on the NAS, every one 401s:
- agent_sdk/server.py: the session-end post-mortem flush
(/api/journals/me/entries), A2A persistence + offline fallback
(/api/a2a/*), and the stopped-without-transition auto-substitute
(/api/tasks/auto-substitute) — all sent only X-Agent-ID/Role, so each
401'd 'Missing X-Agent-Token'. Add a shared _agent_headers() helper
(mirroring flow_server._build_headers) and route all four through it.
- agent_sdk/secretary_driver.py: _headers() sent the token but not the
team, so the HMAC gate 401'd with signature mismatch (secretary is
board-team; token signed with team='board', verified with team='').
Add the team header.
- mcp/git_readonly.py: the read-only git MCP sent only X-Agent-ID/Role
— no token, no team — so /api/git/* 401'd once auth was armed. Convert
the static _HEADERS to a _headers() helper with team + token.
- runtime/orchestrator.py: the cell-PM auto-submit self-API call acted
as a PM with a hand-built {X-Agent-ID, X-Agent-Role} dict — no token,
no team — 401ing under auth-required. Add _agent_api_headers(uuid,
role) mirroring _system_api_headers, and use it.
Tests: _agent_headers round-trip (token + team, team-omitted when None),
_agent_api_headers carries a signed PM token + team.
52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
"""The SDK server's direct orchestrator calls must carry the agent HMAC
|
|
token + team, or the API's ``ROBOCO_AGENT_AUTH_REQUIRED`` gate 401s with
|
|
"Missing X-Agent-Token" — regression: the session-end post-mortem flush
|
|
(``/api/journals/me/entries``), A2A persistence/fallback, and
|
|
auto-substitute call all built the header dict by hand and omitted both,
|
|
latent until auth was armed on the NAS deploy.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
from typing import TYPE_CHECKING
|
|
|
|
import roboco.agent_sdk.server as srv
|
|
|
|
if TYPE_CHECKING:
|
|
import pytest
|
|
|
|
|
|
def test_agent_headers_carries_token_and_team(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
be_dev_1 = "00000000-0000-0000-0001-000000000001" # role=developer, team=backend
|
|
monkeypatch.setenv("ROBOCO_AGENT_ID", be_dev_1)
|
|
monkeypatch.setenv("ROBOCO_AGENT_ROLE", "developer")
|
|
monkeypatch.setenv("ROBOCO_AGENT_TOKEN", "test-hmac-token")
|
|
importlib.reload(srv)
|
|
|
|
headers = srv._agent_headers()
|
|
|
|
assert headers["X-Agent-ID"] == be_dev_1
|
|
assert headers["X-Agent-Role"] == "developer"
|
|
assert headers["X-Agent-Team"] == "backend"
|
|
assert headers["X-Agent-Token"] == "test-hmac-token"
|
|
|
|
|
|
def test_agent_headers_omits_team_when_none(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
# A team-less agent (the `system` sentinel) confirms the team header is
|
|
# omitted, not sent empty — so the middleware passes "" and matches a
|
|
# token signed with team="".
|
|
monkeypatch.setenv("ROBOCO_AGENT_ID", "00000000-0000-0000-0000-000000000000")
|
|
monkeypatch.setenv("ROBOCO_AGENT_ROLE", "system")
|
|
monkeypatch.setenv("ROBOCO_AGENT_TOKEN", "test-hmac-token")
|
|
importlib.reload(srv)
|
|
|
|
headers = srv._agent_headers()
|
|
|
|
assert "X-Agent-Team" not in headers
|
|
assert headers["X-Agent-Token"] == "test-hmac-token"
|