From 722279e27708aa0489e773e538e61d5202801b0c Mon Sep 17 00:00:00 2001 From: Johannes du Plessis Date: Tue, 9 Jun 2026 16:41:07 -0700 Subject: [PATCH] fix: restore org-wide read access to agent threads (#1474) The viewed-marker feature (#1441) reintroduced an owner-only gate on thread reads, regressing #1425 which made all threads readable by any org user. Reads no longer assert ownership; viewed markers are only written for the thread owner. Co-authored-by: open-swe[bot] --- agent/dashboard/thread_api.py | 4 ++-- tests/test_dashboard_thread_api_activity.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/agent/dashboard/thread_api.py b/agent/dashboard/thread_api.py index 0cebc979..6e5cdfbb 100644 --- a/agent/dashboard/thread_api.py +++ b/agent/dashboard/thread_api.py @@ -428,7 +428,7 @@ async def get_dashboard_thread( raise HTTPException(404, "thread not found") from exc metadata = thread.get("metadata") if isinstance(thread.get("metadata"), dict) else {} - _assert_thread_owner(metadata, login, email) + is_owner = _user_owns_thread(metadata, login, email) messages: list[dict[str, Any]] = [] try: @@ -454,7 +454,7 @@ async def get_dashboard_thread( else None ), ) - if mark_viewed and status != "running": + if mark_viewed and is_owner and status != "running": metadata = await _mark_thread_viewed( client, thread_id, diff --git a/tests/test_dashboard_thread_api_activity.py b/tests/test_dashboard_thread_api_activity.py index 7393d397..60b18d66 100644 --- a/tests/test_dashboard_thread_api_activity.py +++ b/tests/test_dashboard_thread_api_activity.py @@ -83,6 +83,24 @@ async def test_get_dashboard_thread_marks_finished_thread_viewed(monkeypatch) -> assert client.threads.thread["metadata"]["last_viewed_run_id"] == "run-1" +async def test_get_dashboard_thread_readable_by_non_owner(monkeypatch) -> None: + client = FakeClient( + { + "source": "slack", + "github_login": "octocat", + "latest_run_id": "run-1", + "latest_run_status": "success", + }, + "success", + ) + monkeypatch.setattr(thread_api, "langgraph_client", lambda: client) + + result = await thread_api.get_dashboard_thread("tid", "someone-else") + + assert result["status"] == "finished" + assert "last_viewed_run_id" not in client.threads.thread["metadata"] + + async def test_get_dashboard_thread_skips_mark_viewed_when_disabled(monkeypatch) -> None: client = FakeClient( {