diff --git a/agent/dashboard/oauth.py b/agent/dashboard/oauth.py index ea4aeb7f..835de659 100644 --- a/agent/dashboard/oauth.py +++ b/agent/dashboard/oauth.py @@ -66,7 +66,10 @@ def _origin_of(url: str) -> str: return "" scheme = parsed.scheme.lower() host = parsed.hostname.lower() - port = parsed.port + try: + port = parsed.port + except ValueError: + return "" if port is None: return f"{scheme}://{host}" default_port = 443 if scheme == "https" else 80 if scheme == "http" else None diff --git a/tests/test_dashboard_csrf.py b/tests/test_dashboard_csrf.py index d6613918..44aeb532 100644 --- a/tests/test_dashboard_csrf.py +++ b/tests/test_dashboard_csrf.py @@ -92,6 +92,16 @@ async def test_require_same_origin_rejects_null_origin(monkeypatch) -> None: assert exc.value.status_code == 403 +@pytest.mark.asyncio +async def test_require_same_origin_rejects_malformed_port(monkeypatch) -> None: + monkeypatch.setenv("DASHBOARD_BASE_URL", "https://dashboard.example") + + with pytest.raises(HTTPException) as exc: + oauth.require_same_origin(_request(origin="https://dashboard.example:notaport")) + + assert exc.value.status_code == 403 + + @pytest.mark.asyncio async def test_require_same_origin_rejects_unknown_origin(monkeypatch) -> None: monkeypatch.setenv("DASHBOARD_BASE_URL", "https://dashboard.example") diff --git a/ui/src/components/agents/AgentsHome.tsx b/ui/src/components/agents/AgentsHome.tsx index ec099f7e..87d482e0 100644 --- a/ui/src/components/agents/AgentsHome.tsx +++ b/ui/src/components/agents/AgentsHome.tsx @@ -87,10 +87,17 @@ export function AgentsHome() { if (repo) configurable.repo = repo if (repoOverride === null) configurable.repo_explicitly_none = true - void stream.submit( - { messages: [{ type: "human", content: promptContent(prompt, images) }] }, - { config: { configurable } } - ) + stream + .submit( + { messages: [{ type: "human", content: promptContent(prompt, images) }] }, + { config: { configurable } } + ) + .catch(() => { + // Submit failed before the SDK minted a thread id — re-enable the + // prompt instead of leaving it disabled until a reload. + draftRef.current = null + setSubmitting(false) + }) } return (