Skip to content

fix: fence workspace export ownership - #118

Merged
delete-cloud merged 3 commits into
mainfrom
feat-adr-0019-workspace-export-fencing
May 8, 2026
Merged

delete-cloud merged 3 commits into
mainfrom
feat-adr-0019-workspace-export-fencing

Conversation

@delete-cloud

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

Copy link
Copy Markdown
Owner

Summary

  • fence GET /sessions/{session_id}/workspace behind SessionManager.export_workspace_archive so workspace export shares the same owner and active-turn gating as other owner-sensitive HTTP surfaces
  • revalidate ownership after archive export and add focused route plus public-API regressions for active turns, stale owners, and owner-change-during-export races
  • track the scoped ADR-19 task packet in .opencode/prompts/tasks/adr-0019-pr5-workspace-export-fencing.md

Verification

  • uv run pytest tests/ui/test_http_server_workspace_transfer.py -v
  • uv run pytest tests/ui/test_http_server_failover.py -k \"get_events\" -v
  • uv run pytest tests/ui/test_session_manager_public_api.py -k \"export_workspace_archive or capture_checkpoint_rejects_active_turn or capture_checkpoint_rejects_when_turn_lock_is_held or restore_checkpoint_rejects_active_turn or restore_checkpoint_rejects_when_turn_lock_is_held\" -v
  • manual QA: live serve returned 200 for provisioned workspace export with nested/data.json and result.txt, and 409 {\"detail\":\"turn already in progress\"} for export during an active /prompt turn

Summary by CodeRabbit

  • Bug Fixes

    • Workspace export endpoint now validates user ownership before allowing export.
    • Returns HTTP 409 Conflict when export is attempted during active operations or with stale credentials.
  • Documentation

    • Added architecture decision record documenting workspace export authorization and safety requirements.

delete-cloud and others added 2 commits May 8, 2026 19:42
Keep workspace archive export behind the same owner and active-turn fences as other owner-sensitive session surfaces so callers cannot race a live turn or stale lease and get a stale snapshot.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Record the scoped ADR-19 workspace export fencing packet alongside the code change so the bounded engineer-reviewer-verifier loop stays reproducible from the branch itself.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@coderabbitai

coderabbitai Bot commented May 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Rate limit exceeded

@delete-cloud has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 40 minutes and 42 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ea98acf4-2dfb-498b-a684-07774430cd29

📥 Commits

Reviewing files that changed from the base of the PR and between c1411d4 and c93676b.

📒 Files selected for processing (2)
  • coding-agent/src/coding_agent/ui/http_server.py
  • coding-agent/tests/ui/test_http_server_workspace_transfer.py
📝 Walkthrough

Walkthrough

This PR implements ownership fencing for workspace export by adding a SessionManager-level guard that serializes exports with the session turn lock, validates ownership before and after export, and rejects stale owners via fencing tokens. The HTTP endpoint is refactored to delegate to this new method with proper error mapping.

Changes

Workspace Export Ownership Fencing

Layer / File(s) Summary
Architecture & Design
.opencode/prompts/tasks/adr-0019-pr5-workspace-export-fencing.md
ADR defining workspace export fencing requirements: turn lock serialization, ownership/active-turn checks, post-export re-validation, and bounded test scope.
SessionManager Workspace Export Guard
src/coding_agent/ui/session_manager.py
New export_workspace_archive method acquires per-session turn lock, asserts ownership with fencing-token validation, rejects active turns, validates CloudWorkspaceBinding, runs export callback on worker thread, and re-checks ownership.
HTTP Layer Integration
src/coding_agent/ui/http_server.py
GET /sessions/{session_id}/workspace refactored to invoke session_manager.export_workspace_archive with exporter callback; error mapping updated (RuntimeError → 409, SessionOwnershipConflictError → 409).
Cloud Binding Provisioning Refinements
src/coding_agent/ui/http_server.py
Snapshot archive provisioning in create_session now safely retrieves snapshot_archive_base64 via getattr and conditionally populates binding only when value is a string.
Test Infrastructure & Fixtures
tests/ui/test_http_server_workspace_transfer.py
FakeOwnerStore in-memory implementation with UTC-based lease expiration and fencing-token validation; owner_store fixture configures session_manager for test-time owner manipulation.
SessionManager Guard Unit Tests
tests/ui/test_session_manager_public_api.py
Unit tests verify export_workspace_archive raises RuntimeError when turn is in progress or when per-session turn lock is held.
HTTP API Integration Tests
tests/ui/test_http_server_workspace_transfer.py
Integration tests assert GET /sessions/{session_id}/workspace returns HTTP 409 for active turns, stale owners with mismatched fencing tokens, and owner mutations during export.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 With locks and tokens, guards so tight,
Workspace exports now require a right,
Check the owner, check the turn,
Then check again before return,
Stale fences fall, fresh hands unlock the night! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.17% 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 'fix: fence workspace export ownership' directly and specifically describes the main change: adding ownership and active-turn fencing to the GET /sessions/{session_id}/workspace endpoint to prevent stale snapshots.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-adr-0019-workspace-export-fencing

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: 1

🤖 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/http_server.py`:
- Around line 1042-1043: The current except block mapping any RuntimeError to
HTTP 409 can mislabel export failures; in the except RuntimeError as exc handler
for export_workspace_archive_from_config, check if str(exc) == "turn already in
progress" and only then raise HTTPException(status_code=409, detail=...) from
exc; otherwise re-raise the original RuntimeError so it surfaces as a 500.
Mirror the exact guard logic used in send_prompt to locate and update the
handler for export_workspace_archive_from_config.
🪄 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: 35758090-90c8-4b1f-ba7f-79eafbfd0b4b

📥 Commits

Reviewing files that changed from the base of the PR and between 65cadb7 and c1411d4.

📒 Files selected for processing (5)
  • coding-agent/.opencode/prompts/tasks/adr-0019-pr5-workspace-export-fencing.md
  • coding-agent/src/coding_agent/ui/http_server.py
  • coding-agent/src/coding_agent/ui/session_manager.py
  • coding-agent/tests/ui/test_http_server_workspace_transfer.py
  • coding-agent/tests/ui/test_session_manager_public_api.py

Comment thread coding-agent/src/coding_agent/ui/http_server.py Outdated
Only map the expected active-turn runtime conflict to HTTP 409 for workspace export so provider and backend failures continue surfacing as server errors instead of being mislabeled as conflicts.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@delete-cloud
delete-cloud merged commit 388e522 into main May 8, 2026
1 check passed
@delete-cloud
delete-cloud deleted the feat-adr-0019-workspace-export-fencing branch May 8, 2026 14:36
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