feat(sandbox): add plugin execution sandbox with resource limits and …#367
feat(sandbox): add plugin execution sandbox with resource limits and …#367ask-z4ch wants to merge 6 commits into
Conversation
…timeout enforcement Closes utksh1#326 Introduce SandboxConfig Pydantic model, sandbox_executor.py utility, and frontend Task Details integration for resource-limited subprocess execution. - SandboxConfig with defaults (timeout_seconds=120, max_memory_mb=512, max_output_bytes=5MB, allow_network) - sandbox_execute() wraps asyncio.create_subprocess_exec with: - asyncio.wait_for() timeout enforcement - stdout/stderr byte-stream capping at max_output_bytes - resource.setrlimit (RLIMIT_AS, RLIMIT_CPU) via preexec_fn on Linux - SIGTERM -> 3s grace -> SIGKILL escalation - Structured SandboxViolation propagated to task status - Per-plugin sandbox overrides via metadata.json sandbox key - Task-status values: terminated:timeout, terminated:memory_limit, terminated:output_limit - Frontend Task Details: labeled badge with threshold tooltip, sandbox violation error block - 11 new unit tests covering timeout, output cap, SIGKILL, platform guard - Documented sandbox metadata key in PLUGINS.md Signed-off-by: ask-z4ch <askz4ch@users.noreply.github.com>
The sandbox executor refactored _execute_command to return (output, exit_code, violation) instead of (output, exit_code). All mocked call sites in integration tests must return None as the third element to match the new signature. Closes utksh1#326 Signed-off-by: ask-z4ch <askz4ch@users.noreply.github.com>
utksh1
left a comment
There was a problem hiding this comment.
Requesting changes. The sandbox direction is useful, but this is not safe enough to merge yet: memory-limit termination is not reliably classified as terminated:memory_limit, the old timeout argument path is effectively replaced instead of preserving compatibility, and output-limit handling can still broadcast/read chunks beyond the capped stored output. Please make the limit behavior precise and add tests for timeout, memory, output, cancellation, and legacy timeout compatibility.
|
Thanks for following up. Clarifying the change request so it is actionable: Why this is blocked: What to do next:
|
- Add trio>=0.27.0 to requirements-dev.txt so anyio can parametrize tests over both backends without ModuleNotFoundError - Pin anyio backends to ['asyncio'] via conftest fixture since the codebase uses asyncio.create_task directly and is not trio-compatible - Add ignore_cleanup_errors=True to TemporaryDirectory in conftest.py to prevent Windows PermissionError on SQLite DB cleanup Signed-off-by: ask-z4ch <229467675+ask-z4ch@users.noreply.github.com> Closes utksh1#365
…y classification, legacy compat (Closes utksh1#326) Rewrite sandbox_executor.py per security specification: - Proactive 64KB chunked stream reader for stdout+stderr (no communicate()) - Output limit detection stops reading immediately, terminates process - Timeout enforcement via asyncio.wait_for with SIGTERM->3s->SIGKILL escalation - Memory exhaustion heuristics: SIGSEGV(-11/139), MemoryError string, RSS>=95% - Platform guard: RLIMIT_AS applied only on Linux, graceful no-op elsewhere - try/finally cancellation guard ensures subprocess is never orphaned Core Executor Adapter: - _execute_command signature preserved: (cmd, timeout=None) -> (output, exit_code, violation_reason) - SandboxConfig created internally from global settings - Per-plugin sandbox config handled at execute_task level via timeout override - Returns violation_reason string directly for terminated:* status mapping Models: - SandboxViolation changed to Exception subclass (was BaseModel) - SandboxConfig defaults unchanged Tests: - 16 tests covering: legacy timeout compatibility, signal escalation, memory classification (SIGSEGV, MemoryError, RSS), output truncation, cancellation safety, platform guard, normal completion, config resolution Signed-off-by: ask-z4ch <229467675+ask-z4ch@users.noreply.github.com> Closes utksh1#326
…out=600) signature Preserve original 3-parameter signature for backward compatibility. task_id is accepted but only used for parameter compatibility; SandboxConfig is created internally from the timeout parameter. Signed-off-by: ask-z4ch <229467675+ask-z4ch@users.noreply.github.com>
|
Closing and reopening to force GitHub to re-evaluate mergeability after rebase. No code changes. |
Purpose & Rationale
Plugin subprocesses (nmap, nikto, custom parsers) previously ran with no CPU, memory, or time constraints. A single runaway plugin could degrade the entire local instance — common in the learning and lab environments SecuScan targets. This change introduces a backend sandbox layer that enforces configurable resource limits with structured timeout escalation, surfacing violation reasons in the Task Details view.
Technical Resolution Details
Added
backend/secuscan/sandbox_executor.pywithsandbox_execute()wrapping everyasyncio.create_subprocess_execcall with timeout enforcement (asyncio.wait_for), output byte-stream capping,resource.setrlimitviapreexec_fnon Linux (withplatform.system()guard for macOS/Windows), and a SIGTERM → 3s grace → SIGKILL escalation. CreatedSandboxConfigPydantic model (timeout_seconds=120,max_memory_mb=512,max_output_bytes=5MB,allow_network) andSandboxViolationmodel inmodels.py. ExtendedPluginMetadatawith an optionalsandboxkey for per-plugin overrides. Replaced raw subprocess calls inexecutor.py(_execute_command) withsandbox_execute(), mappingSandboxViolationreasons to distinctterminated:timeout,terminated:memory_limit, andterminated:output_limittask statuses. Updatedfrontend/src/pages/TaskDetails.tsxwith a labeled badge, threshold tooltip, and sandbox violation error block. Documented thesandboxmetadata key inPLUGINS.md. Closes #326.Local Testing Execution
pytest testing/backend/unit/ testing/backend/test_sandbox_executor.py -v --asyncio-mode=strict --timeout=60— 254 tests pass; 2 failures and 2 errors are pre-existing infrastructure issues (missing trio dependency, Windows PermissionError on temp dir cleanup) unrelated to this changeresolve_sandbox_configmergingSandboxViolation(reason="timeout")produced for a sleep-30 process with 1s timeout, andSandboxViolation(reason="output_limit")for a 5000-byte output capped at 100 bytesDesired Review Feedback Type
Focus on the
sandbox_executeSIGTERM → SIGKILL escalation timing and the output-cap truncation logic — these paths are the most safety-critical.Integrity & AI Usage Disclosure
In compliance with the GSSoC 2026 AI Conduct rules, I disclose that AI tools were used solely as learning and boilerplate aids. The final logic was fully reviewed, tested, and manually adapted to match human styling and clean-code design.