Skip to content

Codex/sandbox workspace archive - #1039

Open
FicoHu wants to merge 26 commits into
wecode-ai:mainfrom
FicoHu:codex/sandbox-workspace-archive
Open

Codex/sandbox workspace archive#1039
FicoHu wants to merge 26 commits into
wecode-ai:mainfrom
FicoHu:codex/sandbox-workspace-archive

Conversation

@FicoHu

@FicoHu FicoHu commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added sandbox workspace archival and restoration capabilities to preserve sandbox state across lifecycle operations.
    • Enhanced sandbox creation response with metadata and base URL information for improved recovery and runtime configuration.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The pull request introduces DB-backed sandbox workspace archival and restoration capabilities. A new SandboxWorkspaceArchiveService manages archiving workspace data before sandbox deletion and restoring it after creation. The execution service integrates these operations with database transaction handling. The API schema is updated to include base_url and metadata fields in sandbox creation responses. Comprehensive tests validate the new archival/restore workflows and metadata handling.

Changes

Cohort / File(s) Summary
Core Service Implementation
backend/app/services/execution/__init__.py, backend/app/services/sandbox_workspace_archive.py
Introduces SandboxWorkspaceArchiveService with methods for preparing restore metadata, archiving workspace before deletion, and restoring after creation. Integration hooks added to execution service with database session management and error handling (warnings on archive failures, non-fatal restore errors).
API Schema & Router
executor_manager/schemas/sandbox.py, executor_manager/routers/sandbox.py
Extends CreateSandboxResponse with optional base_url and metadata fields to convey runtime restore information. Router populates these fields in both success and failure paths during sandbox creation.
Execution Service Tests
backend/tests/services/execution/test_sandbox_manager_client.py
Verifies sandbox lifecycle integration: tests that prepare_restore_metadata and restore_sandbox_after_create are invoked during creation, and archive_sandbox_before_delete is invoked during deletion; includes error resilience scenarios.
Archive Service Tests
backend/tests/services/test_sandbox_workspace_archive.py
Validates SandboxWorkspaceArchiveService methods: archival resolves runtime client and persists metadata, restore preparation checks archive availability and sets skip flags, and restoration invokes the workspace restore operation with correct context.
Router Tests
executor_manager/tests/routers/test_sandbox_routes.py
Confirms sandbox creation response includes populated base_url and metadata fields from the prepared sandbox object.

Sequence Diagrams

sequenceDiagram
    participant Client
    participant ExecutionSvc as Execution Service
    participant DB as Database
    participant ArchiveSvc as Archive Service
    participant RuntimeClient as Runtime Client

    Client->>ExecutionSvc: create_sandbox()
    ExecutionSvc->>DB: Open SessionLocal transaction
    ExecutionSvc->>ArchiveSvc: prepare_restore_metadata(db)
    ArchiveSvc->>RuntimeClient: Resolve runtime client
    ArchiveSvc->>RuntimeClient: Check archive availability
    ArchiveSvc->>DB: Load task metadata
    ArchiveSvc-->>ExecutionSvc: Return task/restore target
    ExecutionSvc->>RuntimeClient: create_sandbox via API
    RuntimeClient-->>ExecutionSvc: Return sandbox object
    ExecutionSvc->>ArchiveSvc: restore_sandbox_after_create(sandbox)
    ArchiveSvc->>RuntimeClient: restore_workspace(executor context)
    RuntimeClient-->>ArchiveSvc: Restoration result
    ArchiveSvc-->>ExecutionSvc: Return restore result
    ExecutionSvc->>DB: Commit transaction
    ExecutionSvc->>DB: Close session
    ExecutionSvc-->>Client: CreateSandboxResponse with metadata
Loading
sequenceDiagram
    participant Client
    participant ExecutionSvc as Execution Service
    participant DB as Database
    participant ArchiveSvc as Archive Service
    participant RuntimeClient as Runtime Client
    participant SandboxMgr as Sandbox Manager API

    Client->>ExecutionSvc: delete_sandbox(sandbox_id)
    ExecutionSvc->>DB: Open SessionLocal session
    ExecutionSvc->>ArchiveSvc: archive_sandbox_before_delete(db, sandbox_id)
    ArchiveSvc->>RuntimeClient: Resolve runtime client
    ArchiveSvc->>RuntimeClient: get_sandbox(sandbox_id)
    RuntimeClient-->>ArchiveSvc: Sandbox pod details
    ArchiveSvc->>DB: Load task from sandbox metadata
    ArchiveSvc->>RuntimeClient: archive_workspace(executor context)
    RuntimeClient-->>ArchiveSvc: Archive result
    ArchiveSvc->>DB: Commit archive metadata
    ArchiveSvc-->>ExecutionSvc: Archive complete (or swallow warning)
    ExecutionSvc->>SandboxMgr: HTTP DELETE sandbox
    SandboxMgr-->>ExecutionSvc: Deletion response
    ExecutionSvc->>DB: Close session
    ExecutionSvc-->>Client: Deletion result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hopping through archives, restoring with care,
Workspaces preserved in the database's lair,
Metadata restored when new sandboxes rise,
Clean deletion paths—no data demise,
A bunny's delight, this robust design!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Codex/sandbox workspace archive' directly reflects the main feature being added: sandbox workspace archival and restoration functionality during the sandbox lifecycle. The changes implement comprehensive archive/restore support across multiple services and test files, making this title an accurate summary of the changeset's primary purpose.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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.

🧹 Nitpick comments (3)
backend/tests/services/test_sandbox_workspace_archive.py (1)

58-82: 💤 Low value

Minor: Unnecessary @pytest.mark.asyncio decorator.

prepare_restore_metadata is a synchronous method (no async def, no await in test). The @pytest.mark.asyncio decorator on line 58 is unnecessary here and could be removed for clarity.

Suggested fix
-@pytest.mark.asyncio
-async def test_prepare_restore_metadata_sets_skip_git_clone_when_archive_available():
+def test_prepare_restore_metadata_sets_skip_git_clone_when_archive_available():
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/tests/services/test_sandbox_workspace_archive.py` around lines 58 -
82, The test function
test_prepare_restore_metadata_sets_skip_git_clone_when_archive_available is
marked with `@pytest.mark.asyncio` but calls the synchronous
SandboxWorkspaceArchiveService.prepare_restore_metadata (no async/await); remove
the unnecessary decorator from the test declaration so it runs as a normal sync
test, leaving the rest of the test (patches of service._load_task and
archive_service.check_archive_available, the call to
service.prepare_restore_metadata, and the assertions) unchanged.
backend/app/services/sandbox_workspace_archive.py (1)

93-97: ⚡ Quick win

Missing return type annotation for archive_sandbox_before_delete.

The method returns archive_info (from archive_service.archive_workspace) or None, but lacks a return type hint. Per coding guidelines, public functions should have type hints.

Suggested fix
+    from app.services.workspace_archive.archive_service import ArchiveInfo
+
     async def archive_sandbox_before_delete(
         self,
         db: Session,
         sandbox_id: str,
-    ):
+    ) -> Optional["ArchiveInfo"]:
         """Archive a running task-backed sandbox before it is deleted."""

Alternatively, if ArchiveInfo import causes cycles, use a string annotation or Any:

     async def archive_sandbox_before_delete(
         self,
         db: Session,
         sandbox_id: str,
-    ):
+    ) -> Optional[Any]:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/services/sandbox_workspace_archive.py` around lines 93 - 97, Add
an explicit return type to archive_sandbox_before_delete: it can return the
ArchiveInfo from archive_service.archive_workspace or None, so annotate it as
Optional[ArchiveInfo] (or use a forward-string annotation "ArchiveInfo" or
typing.Any if importing ArchiveInfo would introduce an import cycle). Update the
function signature for archive_sandbox_before_delete to include the chosen
return type and add the necessary typing import (Optional) or use the string/Any
approach to avoid cyclic imports.
backend/app/services/execution/__init__.py (1)

209-222: 💤 Low value

Redundant pass statement after logging.

Line 220 has pass after the warning log which is unnecessary.

Suggested fix
         except Exception as archive_error:
             logger.warning(
                 "Failed to archive sandbox %s before deletion: %s",
                 sandbox_id,
                 archive_error,
             )
-            pass
         finally:
             db.close()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/services/execution/__init__.py` around lines 209 - 222, The
except block in the try/except around SessionLocal usage contains a redundant
"pass" after logging; remove the unnecessary "pass" so the except only logs the
error (logger.warning(...) for
sandbox_workspace_archive_service.archive_sandbox_before_delete) and then allows
the finally block to run (db.close()); ensure no other logic depends on the pass
before committing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/app/services/execution/__init__.py`:
- Around line 209-222: The except block in the try/except around SessionLocal
usage contains a redundant "pass" after logging; remove the unnecessary "pass"
so the except only logs the error (logger.warning(...) for
sandbox_workspace_archive_service.archive_sandbox_before_delete) and then allows
the finally block to run (db.close()); ensure no other logic depends on the pass
before committing.

In `@backend/app/services/sandbox_workspace_archive.py`:
- Around line 93-97: Add an explicit return type to
archive_sandbox_before_delete: it can return the ArchiveInfo from
archive_service.archive_workspace or None, so annotate it as
Optional[ArchiveInfo] (or use a forward-string annotation "ArchiveInfo" or
typing.Any if importing ArchiveInfo would introduce an import cycle). Update the
function signature for archive_sandbox_before_delete to include the chosen
return type and add the necessary typing import (Optional) or use the string/Any
approach to avoid cyclic imports.

In `@backend/tests/services/test_sandbox_workspace_archive.py`:
- Around line 58-82: The test function
test_prepare_restore_metadata_sets_skip_git_clone_when_archive_available is
marked with `@pytest.mark.asyncio` but calls the synchronous
SandboxWorkspaceArchiveService.prepare_restore_metadata (no async/await); remove
the unnecessary decorator from the test declaration so it runs as a normal sync
test, leaving the rest of the test (patches of service._load_task and
archive_service.check_archive_available, the call to
service.prepare_restore_metadata, and the assertions) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6643df6a-fa4a-4f60-bb58-4b883aae821d

📥 Commits

Reviewing files that changed from the base of the PR and between 76f1c37 and df1b7b0.

📒 Files selected for processing (7)
  • backend/app/services/execution/__init__.py
  • backend/app/services/sandbox_workspace_archive.py
  • backend/tests/services/execution/test_sandbox_manager_client.py
  • backend/tests/services/test_sandbox_workspace_archive.py
  • executor_manager/routers/sandbox.py
  • executor_manager/schemas/sandbox.py
  • executor_manager/tests/routers/test_sandbox_routes.py

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