[scan] secretary token signs over real team (board) not empty — fixes /api/secretary/* 401 (L31-class)

This commit is contained in:
Renn F
2026-07-06 13:38:09 +02:00
parent 856a03de24
commit 0dfd45cafb
2 changed files with 33 additions and 1 deletions
+5 -1
View File
@@ -4413,7 +4413,11 @@ class AgentOrchestrator:
cli_model=cli_model, cli_model=cli_model,
api_url=api_url, api_url=api_url,
agent_uuid=agent_uuid, agent_uuid=agent_uuid,
agent_token=issue_agent_token(agent_uuid, "secretary", ""), agent_token=issue_agent_token(
agent_uuid,
"secretary",
AGENTS[SECRETARY_AGENT_ID].team.value,
),
provider_base_url=route.base_url, provider_base_url=route.base_url,
provider_auth_token=route.auth_token, provider_auth_token=route.auth_token,
provider_type=route.provider_type.value, provider_type=route.provider_type.value,
@@ -4,6 +4,12 @@ from __future__ import annotations
from unittest.mock import MagicMock from unittest.mock import MagicMock
from roboco.agents_config import (
get_agent_team,
issue_agent_token,
verify_agent_token,
)
from roboco.foundation.identity import AGENTS
from roboco.runtime.orchestrator import ( from roboco.runtime.orchestrator import (
SECRETARY_AGENT_ID, SECRETARY_AGENT_ID,
AgentOrchestrator, AgentOrchestrator,
@@ -57,3 +63,25 @@ def test_resolve_secretary_host_paths_has_claude_and_prompt() -> None:
assert "claude" in paths assert "claude" in paths
assert "prompt" in paths assert "prompt" in paths
assert SECRETARY_AGENT_ID in str(paths["prompt"]) assert SECRETARY_AGENT_ID in str(paths["prompt"])
def test_secretary_token_signs_over_real_team_not_empty(monkeypatch) -> None:
"""The secretary token must verify against the (id, role, team) the
secretary driver actually sends. secretary_driver._headers sends
X-Agent-Team = get_agent_team(uuid) = the secretary's real team ("board"),
so the token issued at spawn (orchestrator _spawn_secretary_container) must
be signed over that same team — not "" — or every /api/secretary/* call
401s with "signature mismatch" under ROBOCO_AGENT_AUTH_REQUIRED.
"""
monkeypatch.setenv("ROBOCO_AGENT_AUTH_SECRET", "x" * 32)
secretary = AGENTS[SECRETARY_AGENT_ID]
agent_uuid = str(secretary.uuid)
team = secretary.team.value
assert team # the bug was signing "" — the secretary IS on a team
token = issue_agent_token(agent_uuid, "secretary", team) # mirrors spawn line
# secretary_driver._headers sends X-Agent-ID=uuid, role=secretary,
# X-Agent-Team=get_agent_team(uuid).
assert verify_agent_token(
token, agent_uuid, "secretary", get_agent_team(agent_uuid)
)