Skip to content

Bubblewrap

minisweagent.environments.extra.bubblewrap

Bubblewrap is a low-level, unprivileged sandboxing tool for Linux that enables running applications in isolated environments with restricted access to the operating system and user data. This environment uses bubblewrap to execute commands in a sandboxed environment.

Warning

This environment is experimental.

Warning

This environment is not supported on Windows.

BubblewrapEnvironmentConfig dataclass

BubblewrapEnvironmentConfig(
    cwd: str = "",
    env: dict[str, str] = dict(),
    timeout: int = 30,
    executable: str = getenv(
        "MSWEA_BUBBLEWRAP_EXECUTABLE", "bwrap"
    ),
    wrapper_args: list[str] = (
        lambda: [
            "--unshare-user-try",
            "--ro-bind",
            "/usr",
            "/usr",
            "--ro-bind",
            "/bin",
            "/bin",
            "--ro-bind",
            "/lib",
            "/lib",
            "--ro-bind",
            "/lib64",
            "/lib64",
            "--ro-bind",
            "/etc",
            "/etc",
            "--tmpfs",
            "/tmp",
            "--proc",
            "/proc",
            "--dev",
            "/dev",
            "--new-session",
            "--setenv",
            "PATH",
            "/usr/local/bin:/usr/sbin:/usr/bin:/bin",
        ]
    )(),
)

cwd class-attribute instance-attribute

cwd: str = ''

Working directory for the sandbox.

env class-attribute instance-attribute

env: dict[str, str] = field(default_factory=dict)

Dictionary of environment variables to set in the sandbox.

timeout class-attribute instance-attribute

timeout: int = 30

Timeout for the command in seconds.

executable class-attribute instance-attribute

executable: str = getenv(
    "MSWEA_BUBBLEWRAP_EXECUTABLE", "bwrap"
)

Path to the bubblewrap executable.

wrapper_args class-attribute instance-attribute

wrapper_args: list[str] = field(
    default_factory=lambda: [
        "--unshare-user-try",
        "--ro-bind",
        "/usr",
        "/usr",
        "--ro-bind",
        "/bin",
        "/bin",
        "--ro-bind",
        "/lib",
        "/lib",
        "--ro-bind",
        "/lib64",
        "/lib64",
        "--ro-bind",
        "/etc",
        "/etc",
        "--tmpfs",
        "/tmp",
        "--proc",
        "/proc",
        "--dev",
        "/dev",
        "--new-session",
        "--setenv",
        "PATH",
        "/usr/local/bin:/usr/sbin:/usr/bin:/bin",
    ]
)

Arguments to pass to the bubblewrap executable.

BubblewrapEnvironment

BubblewrapEnvironment(
    *,
    config_class: type = BubblewrapEnvironmentConfig,
    logger: Logger | None = None,
    **kwargs,
)

This class executes bash commands in a bubblewrap environment and a separate working directory for each environment. See BubblewrapEnvironmentConfig for kwargs.

Source code in src/minisweagent/environments/extra/bubblewrap.py
69
70
71
72
73
74
75
76
77
78
def __init__(
    self, *, config_class: type = BubblewrapEnvironmentConfig, logger: logging.Logger | None = None, **kwargs
):
    """This class executes bash commands in a bubblewrap environment and a separate working
    directory for each environment. See `BubblewrapEnvironmentConfig` for kwargs.
    """
    self.logger = logger or logging.getLogger("minisweagent.environment")
    self.config = config_class(**kwargs)
    self.working_dir = Path(tempfile.gettempdir()) / f"minisweagent-{uuid.uuid4().hex[:8]}"
    self.working_dir.mkdir(parents=True)

logger instance-attribute

logger = logger or getLogger('minisweagent.environment')

config instance-attribute

config = config_class(**kwargs)

working_dir instance-attribute

working_dir = Path(gettempdir()) / f"minisweagent-{hex[:8]}"

execute

execute(
    command: str,
    cwd: str = "",
    *,
    timeout: int | None = None,
) -> dict[str, Any]

Execute a command in the bubblewrap environment and return the result as a dict.

Source code in src/minisweagent/environments/extra/bubblewrap.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def execute(self, command: str, cwd: str = "", *, timeout: int | None = None) -> dict[str, Any]:
    """Execute a command in the bubblewrap environment and return the result as a dict."""
    cwd = cwd or self.config.cwd or str(self.working_dir)

    cmd = [self.config.executable] + self.config.wrapper_args + ["--bind", cwd, cwd, "--chdir", cwd]

    # Add environment variables
    for key, value in self.config.env.items():
        cmd.extend(["--setenv", key, value])

    cmd.extend(["bash", "-c", command])

    result = subprocess.run(
        cmd,
        text=True,
        timeout=timeout or self.config.timeout,
        encoding="utf-8",
        errors="replace",
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
    )
    return {"output": result.stdout, "returncode": result.returncode}

cleanup

cleanup()
Source code in src/minisweagent/environments/extra/bubblewrap.py
103
104
105
def cleanup(self):
    if self.working_dir.exists():
        shutil.rmtree(self.working_dir)

get_template_vars

get_template_vars() -> dict[str, Any]
Source code in src/minisweagent/environments/extra/bubblewrap.py
111
112
def get_template_vars(self) -> dict[str, Any]:
    return asdict(self.config) | platform.uname()._asdict()