Skip to content

fix: clean workspace after snapshot import failure - #140

Merged
delete-cloud merged 1 commit into
mainfrom
fix/snapshot-import-cleanup
May 12, 2026
Merged

delete-cloud merged 1 commit into
mainfrom
fix/snapshot-import-cleanup

Conversation

@delete-cloud

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

Copy link
Copy Markdown
Owner

Summary

  • skip Docker cleanup when snapshot import fails before any container phase can start
  • remove the allocated workspace directory on pre-container import failures
  • add regression coverage for invalid snapshot archives leaving no workspace directory

Validation

  • uv run pytest tests/coding_agent/environment/test_docker_workspace_provider.py -k "snapshot_import_fails_before_containers" -q
  • uv run pytest tests/coding_agent/environment/test_docker_workspace_provider.py -q
  • uv run basedpyright --level error src/coding_agent/environment/docker_workspace_provider.py tests/coding_agent/environment/test_docker_workspace_provider.py
  • uv run ruff format --check src/coding_agent/environment/docker_workspace_provider.py tests/coding_agent/environment/test_docker_workspace_provider.py
  • git diff --check

Summary by CodeRabbit

  • Bug Fixes

    • Improved cleanup of Docker resources when workspace provisioning fails
    • Enhanced error diagnostics when provisioning encounters issues
  • Tests

    • Added regression test to verify proper workspace cleanup during snapshot failures

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Docker workspace provisioning now tracks snapshot extraction success with a docker_cleanup_needed flag. The flag is initialized to False, set to True after snapshot archive extraction, and used in the exception handler to conditionally remove containers only when Docker operations may have started. A regression test validates cleanup behavior when snapshot import fails early.

Changes

Docker cleanup conditional logic

Layer / File(s) Summary
Docker cleanup flag initialization and conditional handling
coding-agent/src/coding_agent/environment/docker_workspace_provider.py
Initialize docker_cleanup_needed flag to False, set to True after snapshot extraction succeeds, and use it in exception handler to conditionally remove setup and main containers with cleanup failure notes attached to the original exception. Workspace directory removal uses ignore_errors based on whether Docker cleanup was expected.
Regression test for early snapshot failure cleanup
coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py
New test validates that provisioning raises an exception when snapshot import fails, removes the workspace directory, and does not attempt any Docker cleanup operations when containers were never started.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through cleanup paths so fine,
Flags tracking when to close the Docker line,
When snapshots fail before containers bloom,
The workspace clears without the Docker zoom—
No cleanup ghosts, just clean and tidy room! 🧹

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 clearly and concisely summarizes the main change: fixing workspace cleanup after snapshot import failures, which is the primary objective of the PR.
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 fix/snapshot-import-cleanup

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/environment/docker_workspace_provider.py`:
- Around line 413-414: The docker_cleanup_needed flag is set before calling
_run_docker_setup_phase_if_configured, causing cleanup to run even when that
helper exits early during pre-subprocess validations; change the logic so
docker_cleanup_needed is set only when Docker execution actually begins (e.g.,
after the code path that invokes subprocess.run or by returning a
boolean/raising a specific signal from _run_docker_setup_phase_if_configured
indicating “Docker invoked”). Update either the call site that currently sets
docker_cleanup_needed or modify _run_docker_setup_phase_if_configured to return
an indicator (true when subprocess.run was called) and set docker_cleanup_needed
based on that, ensuring pre-validation failures
(network/timeout/secret_env_allowlist/missing env) do not trigger cleanup.

In
`@coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py`:
- Around line 878-902: The test currently lets any Exception satisfy
pytest.raises and thus can pass when fake_run raises RuntimeError; modify
fake_run to record calls (e.g., set a local flag like docker_run_called=True)
instead of raising, or have it set the flag and raise a clear sentinel if you
prefer; then call provision_cloud_binding_from_config as before inside
pytest.raises(...) for the specific snapshot-import error, and after the call
assert the docker_run_called flag is False (or assert subprocess.run was not
called via monkeypatch). Update references to fake_run,
monkeypatch.setattr(subprocess, "run", fake_run), and
provision_cloud_binding_from_config to implement and assert the call-tracking so
the test fails if cleanup was invoked.
🪄 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: 9bd2bd4e-a6f4-4304-9c8e-1925ad9ef832

📥 Commits

Reviewing files that changed from the base of the PR and between 14a5b0f and 4f3d82d.

📒 Files selected for processing (2)
  • coding-agent/src/coding_agent/environment/docker_workspace_provider.py
  • coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py

Comment on lines +413 to 414
docker_cleanup_needed = True
_run_docker_setup_phase_if_configured(provider_config, config, binding)

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 | 🟡 Minor | ⚡ Quick win

Delay docker_cleanup_needed until Docker execution is actually possible.

Line 413 sets the flag before _run_docker_setup_phase_if_configured(), but that helper still has several pre-subprocess.run() validation exits (network, timeout_seconds, secret_env_allowlist, missing env vars). Those failures will still take the Docker cleanup path even though no container phase started, and a broken/missing Docker CLI can then leave workspace_root behind again. Consider splitting setup validation from execution, or otherwise deriving this flag from “we actually invoked Docker” rather than “we finished snapshot extraction.”

🤖 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/environment/docker_workspace_provider.py`
around lines 413 - 414, The docker_cleanup_needed flag is set before calling
_run_docker_setup_phase_if_configured, causing cleanup to run even when that
helper exits early during pre-subprocess validations; change the logic so
docker_cleanup_needed is set only when Docker execution actually begins (e.g.,
after the code path that invokes subprocess.run or by returning a
boolean/raising a specific signal from _run_docker_setup_phase_if_configured
indicating “Docker invoked”). Update either the call site that currently sets
docker_cleanup_needed or modify _run_docker_setup_phase_if_configured to return
an indicator (true when subprocess.run was called) and set docker_cleanup_needed
based on that, ensuring pre-validation failures
(network/timeout/secret_env_allowlist/missing env) do not trigger cleanup.

Comment on lines +878 to +902
def fake_run(
command: list[str], **kwargs: object
) -> subprocess.CompletedProcess[str]:
del kwargs
raise RuntimeError(
f"docker cleanup should not run before containers: {command}"
)

monkeypatch.setattr(subprocess, "run", fake_run)

with pytest.raises(Exception):
_ = provision_cloud_binding_from_config(
_docker_config(
{
"workspace_root": str(workspace_root),
"docker_binary": "/usr/bin/docker",
}
),
{
"kind": "docker",
"snapshot_archive_base64": "not a valid workspace archive",
},
)

assert list(workspace_root.iterdir()) == []

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 | 🟡 Minor | ⚡ Quick win

This regression test still passes if cleanup is incorrectly invoked.

Line 888 accepts any Exception, including the RuntimeError raised by fake_run() when Docker cleanup is attempted. That means the test can go green on the exact behavior it is meant to catch. Track whether subprocess.run was called and assert it stayed false, or narrow the expected exception to the snapshot-import failure itself.

Suggested tightening
+    cleanup_attempted = False
+
     def fake_run(
         command: list[str], **kwargs: object
     ) -> subprocess.CompletedProcess[str]:
+        nonlocal cleanup_attempted
         del kwargs
+        cleanup_attempted = True
         raise RuntimeError(
             f"docker cleanup should not run before containers: {command}"
         )

     monkeypatch.setattr(subprocess, "run", fake_run)

     with pytest.raises(Exception):
         _ = provision_cloud_binding_from_config(
             _docker_config(
@@
             },
         )

+    assert cleanup_attempted is False
     assert list(workspace_root.iterdir()) == []
🧰 Tools
🪛 Ruff (0.15.12)

[warning] 888-888: Do not assert blind exception: Exception

(B017)

🤖 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/tests/coding_agent/environment/test_docker_workspace_provider.py`
around lines 878 - 902, The test currently lets any Exception satisfy
pytest.raises and thus can pass when fake_run raises RuntimeError; modify
fake_run to record calls (e.g., set a local flag like docker_run_called=True)
instead of raising, or have it set the flag and raise a clear sentinel if you
prefer; then call provision_cloud_binding_from_config as before inside
pytest.raises(...) for the specific snapshot-import error, and after the call
assert the docker_run_called flag is False (or assert subprocess.run was not
called via monkeypatch). Update references to fake_run,
monkeypatch.setattr(subprocess, "run", fake_run), and
provision_cloud_binding_from_config to implement and assert the call-tracking so
the test fails if cleanup was invoked.

@delete-cloud
delete-cloud merged commit 3cd6bc4 into main May 12, 2026
1 check passed
@delete-cloud
delete-cloud deleted the fix/snapshot-import-cleanup branch May 12, 2026 13:34
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