Source code for dash_evals.runner.solvers.write_to_sandbox

"""Solver to write extracted code to the workspace filesystem."""

import tempfile
from pathlib import Path

from inspect_ai.solver import Generate, Solver, TaskState, solver
from inspect_ai.util import sandbox


def _get_sandbox_type(state: TaskState) -> str:
    """Determine sandbox type from workspace path in metadata.

    Returns:
        'container' if workspace is /workspace (podman/docker)
        'local' if workspace is a host filesystem path
        'none' if no workspace is set
    """
    workspace = state.metadata.get("workspace")
    if not workspace:
        return "none"
    if workspace == "/workspace":
        return "container"
    return "local"


async def _write_to_container(state: TaskState, code: str, target_path: str) -> TaskState:
    """Write code to container sandbox at /workspace.

    Container sandboxes are ephemeral, so writing to /workspace is safe.
    """
    sb = sandbox()
    full_path = f"/workspace/{target_path}"
    await sb.write_file(full_path, code)
    return state


async def _write_to_local(state: TaskState, code: str, target_path: str) -> TaskState:
    """Write code to local sandbox temp directory.

    SAFETY: Only writes to temp directories to prevent accidental
    modification of source templates.
    """
    workspace_path_str = state.metadata.get("workspace")

    # This function is only called when sandbox_type is "local", meaning
    # workspace is set and is a host path (not None, not /workspace)
    assert workspace_path_str is not None

    # SAFETY CHECK: Verify workspace is in temp directory
    temp_dir = tempfile.gettempdir()
    if not workspace_path_str.startswith(temp_dir):
        state.metadata["setup_error"] = (
            f"SAFETY: Refusing to write to non-temp directory: {workspace_path_str}. "
            f"Expected path starting with {temp_dir}"
        )
        return state

    sb = sandbox()
    full_path = f"{workspace_path_str}/{target_path}"
    await sb.write_file(full_path, code)
    return state


[docs] @solver def write_to_sandbox(target_path: str = "lib/main.dart") -> Solver: """ Write extracted code from state.store to the workspace. This solver reads the "extracted_code" from state.store (set by extract_code) and writes it to the specified path in the workspace directory using the sandbox API. Dispatches to the appropriate handler based on sandbox type: - Container (podman/docker): Write directly to /workspace (ephemeral) - Local: Write to temp directory (with safety validation) Args: target_path: Relative path within workspace to write the code. Default is "lib/main.dart" for Flutter projects. Returns: A solver that writes extracted code to the workspace. """ async def solve(state: TaskState, generate: Generate) -> TaskState: # Early termination if previous solver failed if state.metadata.get("setup_error"): return state # Get extracted code from store (set by extract_code solver) code = state.store.get("extracted_code", "") if not code: # Fallback to metadata for backward compatibility code = state.metadata.get("generated_code", "") if not code: return state sandbox_type = _get_sandbox_type(state) if sandbox_type == "none": # No workspace configured, nothing to do return state elif sandbox_type == "container": return await _write_to_container(state, code, target_path) elif sandbox_type == "local": return await _write_to_local(state, code, target_path) else: state.metadata["setup_error"] = f"Unknown sandbox type: {sandbox_type}" return state return solve