Skip to content

feat: add remote session status API - #125

Merged
delete-cloud merged 1 commit into
mainfrom
feat/adr-0021-pr1-session-ops
May 10, 2026
Merged

delete-cloud merged 1 commit into
mainfrom
feat/adr-0021-pr1-session-ops

Conversation

@delete-cloud

@delete-cloud delete-cloud commented May 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add scoped auth context with stable owner labels, admin token support, and config-backed token label map
  • add GET /sessions with owner filtering and admin visibility
  • expand GET /sessions/{session_id} response with status, turn status, execution binding, and workspace id

Validation

  • uv run ruff check src/coding_agent/ui/auth.py src/coding_agent/ui/http_server.py src/coding_agent/ui/schemas.py tests/ui/test_security.py tests/ui/test_http_server.py
  • uv run pytest tests/ui/test_http_server.py tests/ui/test_security.py -q
  • uv run pytest tests/ui/test_security.py tests/ui/test_http_server.py tests/ui/test_session_manager_public_api.py tests/ui/test_session_manager_runtime.py -k "auth or get_session or list_sessions or session_info or origin or binding" -q
  • uv run basedpyright src/coding_agent/ui/auth.py src/coding_agent/ui/http_server.py src/coding_agent/ui/schemas.py src/coding_agent/ui/session_manager.py (0 errors, warnings only)

Summary by CodeRabbit

  • New Features

    • Bearer token authentication support alongside API keys
    • User and admin authentication scopes with role-based access controls
    • New session listing endpoint with role-based filtering (users see only their own sessions, admins see all)
    • Enhanced session details including status, timestamps, and workspace information
    • Token label mapping for improved token organization
  • Refactor

    • Simplified authentication configuration with environment variable support
  • Tests

    • Added coverage for session access control and authentication scope validation

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 10, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR refactors HTTP API authentication to center on an AuthContext object that captures authenticated scope, token digest, and owner label. It introduces server-side config loading for user/admin tokens with optional label mapping, enables per-session ownership tracking, and adds role-based access control to session listing and detail endpoints.

Changes

Auth Context & Session Ownership

Layer / File(s) Summary
Auth Context & Data Shape
src/coding_agent/ui/auth.py
Adds AuthContext dataclass with scope, token, digest, and owner label. Introduces _ConfiguredAuth and _server_config_auth() supporting direct tokens, env-var indirection, and optional token_label_map for custom owner labels.
Token Parsing & Validation
src/coding_agent/ui/auth.py
Implements _provided_tokens() to extract X-API-Key and Authorization headers. Adds auth_context_from_headers() to validate tokens, compute SHA-256 digest, resolve owner label, and return AuthContext or raise 401. Updates verify_api_key() to delegate to the context function.
Session Response Schemas
src/coding_agent/ui/schemas.py
Adds SessionSummaryResponse with status, turn_status, timestamps, execution binding, and workspace ID. Introduces SessionListResponse wrapper. Reformats CreateSessionRequest provider field to multi-line Literal.
Session Data Enrichment
src/coding_agent/ui/session_manager.py
Expands Session.as_dict() to compute turn_running from task state, derive status/turn_status, and include session_id, updated_at, execution_binding, and workspace_id fields.
HTTP Server Integration
src/coding_agent/ui/http_server.py
Adds session access control helpers. Extends _session_origin_from_request to record owner_label and auth_scope. Updates POST /sessions to accept auth_context and pass to origin builder. Adds GET /sessions list endpoint with owner filtering. Updates GET /sessions/{id} to return SessionSummaryResponse with access control (404 for non-owners).
Tests & Configuration
tests/ui/test_http_server.py, tests/ui/test_security.py
Adds _write_auth_config() helper for temp config. Tests auth context derivation (scope, digest mapping, admin scope). Tests session list filtering (user vs. admin visibility) and access control (user cannot access other user's sessions). Validates response payload fields.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • delete-cloud/Coding-Agent-Loop#123: Introduces multi-header auth parsing and config loading that this PR builds upon with owner-label tracking and session access control.

Poem

🐰 A carrot-loving rabbit checks who owns each session,
With context clues and digests—a secure possession!
Admins see all, users see their own precious store,
Authentication strengthened like a warren's reinforced door. 🔐

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add remote session status API' accurately summarizes the main addition: new endpoints and authentication features for session status retrieval, specifically the GET /sessions endpoint with owner filtering and expanded GET /sessions/{session_id} response.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/adr-0021-pr1-session-ops

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@coding-agent/src/coding_agent/ui/auth.py`:
- Around line 106-112: The current code silently disables auth when
raw_server_config is not a dict; instead, if CODING_AGENT_SERVER_CONFIG is set
and raw_server_config is not a mapping, fail closed by raising an error. Change
the block that checks raw_server_config (the variable raw_server_config and the
early return that constructs _ConfiguredAuth) to detect whether
CODING_AGENT_SERVER_CONFIG is present
(os.environ.get("CODING_AGENT_SERVER_CONFIG") or equivalent) and, when present
and raw_server_config is not a dict, raise a ValueError or RuntimeError with a
clear message like "Invalid CODING_AGENT_SERVER_CONFIG: 'server' must be a
mapping" rather than returning a permissive _ConfiguredAuth.

In `@coding-agent/src/coding_agent/ui/http_server.py`:
- Around line 511-527: The access check in _auth_context_can_access_session
currently denies any non-admin auth_context access when
_session_owner_label(session) is None; update the logic to treat missing
owner_label as a legacy session and allow access for authenticated requests by
first assigning owner_label = _session_owner_label(session) and returning True
when owner_label is None (so legacy sessions remain accessible), otherwise
return owner_label == auth_context.owner_label; keep the existing early returns
for auth_context is None and admin scope.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3df1cc66-e18e-413d-a814-4462c8ab7e0b

📥 Commits

Reviewing files that changed from the base of the PR and between 781d7bb and 30970ed.

📒 Files selected for processing (6)
  • coding-agent/src/coding_agent/ui/auth.py
  • coding-agent/src/coding_agent/ui/http_server.py
  • coding-agent/src/coding_agent/ui/schemas.py
  • coding-agent/src/coding_agent/ui/session_manager.py
  • coding-agent/tests/ui/test_http_server.py
  • coding-agent/tests/ui/test_security.py

Comment on lines +106 to +112
if not isinstance(raw_server_config, dict):
return _ConfiguredAuth(
bearer_token=None,
admin_bearer_token=None,
token_label_map={},
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail closed when explicit server config has an invalid server section type.

With CODING_AGENT_SERVER_CONFIG set, a non-mapping server value currently disables auth silently. That creates a misconfiguration fail-open path.

Suggested fix
-    if not isinstance(raw_server_config, dict):
-        return _ConfiguredAuth(
-            bearer_token=None,
-            admin_bearer_token=None,
-            token_label_map={},
-        )
+    if not isinstance(raw_server_config, dict):
+        raise RuntimeError("server config section must be a mapping")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@coding-agent/src/coding_agent/ui/auth.py` around lines 106 - 112, The current
code silently disables auth when raw_server_config is not a dict; instead, if
CODING_AGENT_SERVER_CONFIG is set and raw_server_config is not a mapping, fail
closed by raising an error. Change the block that checks raw_server_config (the
variable raw_server_config and the early return that constructs _ConfiguredAuth)
to detect whether CODING_AGENT_SERVER_CONFIG is present
(os.environ.get("CODING_AGENT_SERVER_CONFIG") or equivalent) and, when present
and raw_server_config is not a dict, raise a ValueError or RuntimeError with a
clear message like "Invalid CODING_AGENT_SERVER_CONFIG: 'server' must be a
mapping" rather than returning a permissive _ConfiguredAuth.

Comment on lines +511 to +527
def _session_owner_label(session: Session) -> str | None:
origin = session.origin
if origin is None:
return None
owner_label = origin.get("owner_label")
return owner_label if isinstance(owner_label, str) and owner_label else None


def _auth_context_can_access_session(
auth_context: AuthContext | None,
session: Session,
) -> bool:
if auth_context is None:
return True
if auth_context.scope == "admin":
return True
return _session_owner_label(session) == auth_context.owner_label

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify whether any load/backfill path populates missing origin.owner_label
# and whether tests cover legacy unlabeled sessions.
rg -n -C3 --type=py 'owner_label|auth_scope|token_digest|backfill_owner|session\.origin|legacy.*session|unlabeled' src tests

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 164


🏁 Script executed:

git ls-files | head -20

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 1189


🏁 Script executed:

#!/bin/bash
# Find the correct directory structure for the project
find . -type d -name "coding-agent" -o -name "src" -o -name "tests" | head -20

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 129


🏁 Script executed:

#!/bin/bash
# List files in the coding-agent directory if it exists
if [ -d "coding-agent" ]; then
  ls -la coding-agent/ | head -20
  find coding-agent -type f -name "*.py" | grep -E "(test|session)" | head -20
fi

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 2027


🏁 Script executed:

#!/bin/bash
# Search for owner_label and related patterns in correct directories
rg -n -C3 'owner_label' coding-agent/src coding-agent/tests --type=py

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 5987


🏁 Script executed:

#!/bin/bash
# Look at the session models and structures
rg -n -C3 'class.*Session|origin.*=' coding-agent/src --type=py | head -100

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 7419


🏁 Script executed:

#!/bin/bash
# Check for backfill, migration, or fallback logic
rg -n -C3 'backfill|migration|fallback|legacy.*session|unlabeled' coding-agent/src --type=py

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 10948


🏁 Script executed:

#!/bin/bash
# View the backfill_owner_leases method implementation
sed -n '828,880p' coding-agent/src/coding_agent/ui/session_manager.py

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 2248


🏁 Script executed:

#!/bin/bash
# Check what _auth_context_can_access_session does in its entirety
sed -n '519,530p' coding-agent/src/coding_agent/ui/http_server.py

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 398


🏁 Script executed:

#!/bin/bash
# Search for test cases that cover legacy sessions or sessions without owner_label
rg -n -C5 'legacy.*session|session.*legacy|owner_label.*None|unlabeled.*session|without.*owner' coding-agent/tests --type=py

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 23020


🏁 Script executed:

#!/bin/bash
# Search for where _auth_context_can_access_session is called and if there's any fallback
rg -n -B5 -A5 '_auth_context_can_access_session' coding-agent/src --type=py

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 2928


🏁 Script executed:

#!/bin/bash
# Check if there's any logic that handles "no owner_label" case differently
rg -n -C5 'GET /sessions|get_sessions' coding-agent/src/coding_agent/ui/http_server.py --type=py | head -80

Repository: delete-cloud/Coding-Agent-Loop

Length of output: 56


Authenticated non-admin users will be locked out of sessions created before this PR.

The strict equality check in _auth_context_can_access_session() (line 527) denies access to any session where _session_owner_label() returns None. Legacy sessions without origin["owner_label"] will fail this check, making them inaccessible via GET /sessions and GET /sessions/{session_id} even for their original owners.

The backfill_owner_leases() method (called on startup at line 430) only populates the owner lease table, not the origin["owner_label"] field in persisted sessions. Without a migration to backfill missing labels or a fallback in the access logic, this creates a breaking change on rollout. Either populate origin["owner_label"] for existing sessions during startup, or add a fallback condition (e.g., allow access if auth_context is set but origin.owner_label is missing).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@coding-agent/src/coding_agent/ui/http_server.py` around lines 511 - 527, The
access check in _auth_context_can_access_session currently denies any non-admin
auth_context access when _session_owner_label(session) is None; update the logic
to treat missing owner_label as a legacy session and allow access for
authenticated requests by first assigning owner_label =
_session_owner_label(session) and returning True when owner_label is None (so
legacy sessions remain accessible), otherwise return owner_label ==
auth_context.owner_label; keep the existing early returns for auth_context is
None and admin scope.

@delete-cloud
delete-cloud merged commit d073508 into main May 10, 2026
1 check passed
@delete-cloud
delete-cloud deleted the feat/adr-0021-pr1-session-ops branch May 10, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant