Skip to content

Destroy grading sandboxes at pipeline cleanup#279

Merged
ArthurCRodrigues merged 2 commits into
mainfrom
fix/destroy-sandbox-after-grading
Apr 13, 2026
Merged

Destroy grading sandboxes at pipeline cleanup#279
ArthurCRodrigues merged 2 commits into
mainfrom
fix/destroy-sandbox-after-grading

Conversation

@ArthurCRodrigues

Copy link
Copy Markdown
Member

Summary

  • change pipeline sandbox cleanup to destroy used sandboxes instead of returning them to idle
  • clear sandbox reference after cleanup
  • update sandbox cleanup unit tests to assert destroy behavior
  • update pipeline documentation to reflect destroy-on-cleanup semantics

Why

Returning used sandboxes to idle can retain cross-submission workspace state and increase risk of vulnerability exploration and workdir pollution.

Closes #278

Copilot AI review requested due to automatic review settings April 13, 2026 16:31

Copilot AI 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.

Pull request overview

Updates the autograder pipeline’s end-of-run sandbox lifecycle to destroy the sandbox used for a submission (instead of returning it to the idle pool), reducing cross-submission state retention risk.

Changes:

  • Switch pipeline cleanup from release_sandbox to destroy_sandbox and clear the sandbox reference.
  • Update unit tests to assert destroy-on-cleanup behavior.
  • Update pipeline documentation to describe destroy-on-cleanup semantics.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
autograder/autograder.py Changes _cleanup_sandbox to destroy sandboxes and clears pipeline_execution.sandbox.
tests/unit/pipeline/test_sandbox_cleanup.py Updates assertions to expect destroy_sandbox() instead of release_sandbox().
docs/pipeline/README.md Documents destroy-on-cleanup behavior as a pipeline guarantee.
docs/core/pipeline-architecture.md Updates architecture summary to mention sandbox destruction during cleanup.
Comments suppressed due to low confidence (1)

autograder/autograder.py:121

  • pipeline_execution.sandbox is only cleared after a successful destroy_sandbox() call. If destroy_sandbox() raises, the exception handler logs and leaves the sandbox reference attached, contradicting the “clear sandbox reference after cleanup” goal and risking repeated cleanup attempts. Clear the reference in a finally once you’ve captured the sandbox to clean up.
        try:
            sandbox = pipeline_execution.sandbox
            if sandbox:
                from sandbox_manager.manager import get_sandbox_manager
                manager = get_sandbox_manager()
                language = pipeline_execution.submission.language
                manager.destroy_sandbox(language, sandbox)
                pipeline_execution.sandbox = None
                logger.info(
                    "Sandbox destroyed: external_user_id=%s, language=%s",
                    pipeline_execution.submission.user_id,
                    language.value if language else "none",
                )
        except Exception as e:
            # Log error but don't fail the pipeline
            logger.warning(
                "Failed to cleanup sandbox (external_user_id=%s): %s",
                pipeline_execution.submission.user_id,
                str(e),
            )

Comment thread autograder/autograder.py
Comment on lines 87 to 91
pipeline_execution.finish_execution() # Generates GradingResult object in pipeline execution

# Cleanup: Release sandbox back to pool if it was created
# Cleanup: Destroy sandbox if it was created
self._cleanup_sandbox(pipeline_execution)

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

finish_execution() can raise (e.g., missing grade step data / feedback step produced None), which would skip sandbox destruction because cleanup is not in a finally. Wrap finish_execution()/return in try/finally (or move cleanup to finally) so sandbox destruction truly runs even when finalization errors out or the pipeline is INTERRUPTED.

Copilot uses AI. Check for mistakes.
Comment on lines 27 to 40
@@ -39,11 +39,11 @@ def test_cleanup_sandbox_called_after_pipeline_run(mock_get_manager, pipeline_ex
# Let's test _cleanup_sandbox directly to verify it uses the property
pipeline._cleanup_sandbox(pipeline_exec)

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

This test’s docstring says it verifies cleanup “after pipeline run”, but the test calls _cleanup_sandbox() directly and never exercises AutograderPipeline.run() to ensure cleanup is invoked on real execution paths. Either adjust the wording or add a minimal step + real run() invocation to validate the integration behavior being described.

Copilot uses AI. Check for mistakes.
Comment on lines 40 to +42
pipeline._cleanup_sandbox(pipeline_exec)

mock_manager.release_sandbox.assert_called_once_with(Language.PYTHON, mock_sandbox)
mock_manager.destroy_sandbox.assert_called_once_with(Language.PYTHON, mock_sandbox)

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

The new behavior includes clearing the sandbox reference (pipeline_execution.sandbox = None), but the tests only assert destroy_sandbox() was called. Add an assertion that pipeline_exec.sandbox is None after cleanup so the “clear sandbox reference after cleanup” requirement is covered.

Copilot uses AI. Check for mistakes.
Comment thread docs/pipeline/README.md
- Unhandled exceptions set the status to `INTERRUPTED`.
- After all steps (or early exit), `finish_execution()` is called to assemble the final `GradingResult`.
- Sandbox cleanup always runs at the end, regardless of success or failure.
- Sandbox cleanup always runs at the end, regardless of success or failure, and destroys the sandbox used by that submission.

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

Docs state sandbox cleanup “always runs” at the end. In AutograderPipeline.run(), cleanup currently happens after finish_execution() without a finally, so any exception during finalization can skip destruction. Either update the docs to reflect “best effort” cleanup or (preferably) change the implementation to guarantee cleanup via try/finally.

Suggested change
- Sandbox cleanup always runs at the end, regardless of success or failure, and destroys the sandbox used by that submission.
- Sandbox cleanup is attempted at the end as a best-effort step and normally destroys the sandbox used by that submission, but it is not guaranteed if finalization raises an exception before cleanup is reached.

Copilot uses AI. Check for mistakes.
3. If a step fails, execution stops early.
4. `finish_execution()` assembles `GradingResult` from grade/focus/feedback artifacts.
5. Sandbox cleanup runs at the end.
5. Sandbox cleanup runs at the end and destroys any sandbox used by the submission.

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

This statement says sandbox cleanup runs at the end and destroys the sandbox. Today AutograderPipeline.run() calls cleanup after finish_execution() without a finally, so destruction may be skipped if finalization raises. Align this doc with the actual guarantee (or adjust code to make the guarantee true).

Suggested change
5. Sandbox cleanup runs at the end and destroys any sandbox used by the submission.
5. In the normal execution flow, sandbox cleanup is called after finalization to destroy any sandbox used by the submission.

Copilot uses AI. Check for mistakes.
@ArthurCRodrigues
ArthurCRodrigues force-pushed the fix/destroy-sandbox-after-grading branch from b97c6fe to 893da98 Compare April 13, 2026 16:35

@ArthurCRodrigues ArthurCRodrigues left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

OK

@ArthurCRodrigues
ArthurCRodrigues merged commit b8ecb8a into main Apr 13, 2026
3 checks passed
@ArthurCRodrigues
ArthurCRodrigues deleted the fix/destroy-sandbox-after-grading branch April 13, 2026 17: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.

Destroy sandbox after grading execution

2 participants