mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
[auth] Omit UNSIGNED self-call token in dev mode + video-engine test mypy fix
_agent_api_headers sent the UNSIGNED sentinel when ROBOCO_AGENT_AUTH_SECRET was unset, but the dev-mode middleware rejects a presented-but-unverifiable token with 401 signature mismatch (while accepting a missing one). The cell-PM auto-submit self-call 401'd in every dev run, regressing test_auto_submit_cuts_the_pm_turn. Attach the token only when a secret is set. Also fix the FromClause.update mypy error in the per-project video-engine opt-out test (ORM row load + flush).
This commit is contained in:
@@ -169,14 +169,21 @@ def _agent_api_headers(agent_uuid: str, role: str) -> dict[str, str]:
|
|||||||
gate — a hand-built ``{X-Agent-ID, X-Agent-Role}`` dict 401s with
|
gate — a hand-built ``{X-Agent-ID, X-Agent-Role}`` dict 401s with
|
||||||
"Missing X-Agent-Token" under auth-required (F038/F039 — the same gap the
|
"Missing X-Agent-Token" under auth-required (F038/F039 — the same gap the
|
||||||
system-headers helper closes for the system identity).
|
system-headers helper closes for the system identity).
|
||||||
|
|
||||||
|
The token is attached only when ``ROBOCO_AGENT_AUTH_SECRET`` is set: the
|
||||||
|
dev-mode middleware rejects a presented-but-unverifiable token (the
|
||||||
|
``UNSIGNED`` sentinel) with 401 "signature mismatch" while accepting a
|
||||||
|
missing token, so sending ``UNSIGNED`` would turn a clean dev self-call
|
||||||
|
into a 401. With the secret armed the token is signed and verifies.
|
||||||
"""
|
"""
|
||||||
from roboco.agents_config import issue_agent_token
|
from roboco.agents_config import _auth_secret, issue_agent_token
|
||||||
|
|
||||||
team = get_agent_team(agent_uuid) or ""
|
team = get_agent_team(agent_uuid) or ""
|
||||||
headers = {"X-Agent-ID": agent_uuid, "X-Agent-Role": role}
|
headers = {"X-Agent-ID": agent_uuid, "X-Agent-Role": role}
|
||||||
if team:
|
if team:
|
||||||
headers["X-Agent-Team"] = team
|
headers["X-Agent-Team"] = team
|
||||||
headers["X-Agent-Token"] = issue_agent_token(agent_uuid, role, team)
|
if _auth_secret():
|
||||||
|
headers["X-Agent-Token"] = issue_agent_token(agent_uuid, role, team)
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,3 +82,18 @@ def test_agent_api_headers_carry_signed_token_and_team(
|
|||||||
token = headers["X-Agent-Token"]
|
token = headers["X-Agent-Token"]
|
||||||
assert token and token != "UNSIGNED"
|
assert token and token != "UNSIGNED"
|
||||||
assert verify_agent_token(token, be_pm_uuid, role, team)
|
assert verify_agent_token(token, be_pm_uuid, role, team)
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_api_headers_omit_token_when_secret_unset(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
# Dev mode: with no secret set, issue_agent_token returns the UNSIGNED
|
||||||
|
# sentinel, but the dev-mode middleware rejects a presented-but-unverifiable
|
||||||
|
# token with 401 "signature mismatch" while accepting a missing token.
|
||||||
|
# Sending UNSIGNED would 401 the cell-PM auto-submit self-call in every dev
|
||||||
|
# run (the e2e test_auto_submit_cuts_the_pm_turn regression), so the token
|
||||||
|
# header is omitted entirely when the secret is unset.
|
||||||
|
monkeypatch.delenv("ROBOCO_AGENT_AUTH_SECRET", raising=False)
|
||||||
|
be_pm = _foundation.AGENTS["be-pm"]
|
||||||
|
headers = _agent_api_headers(str(be_pm.uuid), be_pm.role.value)
|
||||||
|
assert "X-Agent-Token" not in headers
|
||||||
|
|||||||
@@ -221,11 +221,10 @@ async def test_open_video_task_no_op_when_project_not_opted_in(
|
|||||||
) -> None:
|
) -> None:
|
||||||
await _seed(db_session)
|
await _seed(db_session)
|
||||||
# Flip the per-project opt-in back off — the global flag stays on.
|
# Flip the per-project opt-in back off — the global flag stays on.
|
||||||
await db_session.execute(
|
project = (
|
||||||
ProjectTable.__table__.update()
|
await db_session.execute(select(ProjectTable).where(ProjectTable.slug == SLUG))
|
||||||
.where(ProjectTable.__table__.c.slug == SLUG)
|
).scalar_one()
|
||||||
.values(video_engine_enabled=False)
|
project.video_engine_enabled = False
|
||||||
)
|
|
||||||
await db_session.flush()
|
await db_session.flush()
|
||||||
_enable(monkeypatch)
|
_enable(monkeypatch)
|
||||||
engine = video_engine_module.VideoEngine(db_session)
|
engine = video_engine_module.VideoEngine(db_session)
|
||||||
|
|||||||
Reference in New Issue
Block a user