mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-04-19 09:29:55 +00:00
fix(sandbox): mount media directory read-only inside bwrap sandbox
This commit is contained in:
parent
cef0f3f988
commit
9f96be6e9b
@ -8,14 +8,19 @@ and register it in _BACKENDS below.
|
|||||||
import shlex
|
import shlex
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from nanobot.config.paths import get_media_dir
|
||||||
|
|
||||||
|
|
||||||
def _bwrap(command: str, workspace: str, cwd: str) -> str:
|
def _bwrap(command: str, workspace: str, cwd: str) -> str:
|
||||||
"""Wrap command in a bubblewrap sandbox (requires bwrap in container).
|
"""Wrap command in a bubblewrap sandbox (requires bwrap in container).
|
||||||
|
|
||||||
Only the workspace is bind-mounted read-write; its parent dir (which holds
|
Only the workspace is bind-mounted read-write; its parent dir (which holds
|
||||||
config.json) is hidden behind a fresh tmpfs.
|
config.json) is hidden behind a fresh tmpfs. The media directory is
|
||||||
|
bind-mounted read-only so exec commands can read uploaded attachments.
|
||||||
"""
|
"""
|
||||||
ws = Path(workspace).resolve()
|
ws = Path(workspace).resolve()
|
||||||
|
media = get_media_dir().resolve()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sandbox_cwd = str(ws / Path(cwd).resolve().relative_to(ws))
|
sandbox_cwd = str(ws / Path(cwd).resolve().relative_to(ws))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -33,6 +38,7 @@ def _bwrap(command: str, workspace: str, cwd: str) -> str:
|
|||||||
"--tmpfs", str(ws.parent), # mask config dir
|
"--tmpfs", str(ws.parent), # mask config dir
|
||||||
"--dir", str(ws), # recreate workspace mount point
|
"--dir", str(ws), # recreate workspace mount point
|
||||||
"--bind", str(ws), str(ws),
|
"--bind", str(ws), str(ws),
|
||||||
|
"--ro-bind-try", str(media), str(media), # read-only access to media
|
||||||
"--chdir", sandbox_cwd,
|
"--chdir", sandbox_cwd,
|
||||||
"--", "sh", "-c", command,
|
"--", "sh", "-c", command,
|
||||||
]
|
]
|
||||||
|
|||||||
@ -92,6 +92,22 @@ class TestBwrapBackend:
|
|||||||
assert "/bin" in try_targets
|
assert "/bin" in try_targets
|
||||||
assert "/etc/ssl/certs" in try_targets
|
assert "/etc/ssl/certs" in try_targets
|
||||||
|
|
||||||
|
def test_media_dir_ro_bind(self, tmp_path, monkeypatch):
|
||||||
|
"""Media directory should be read-only mounted inside the sandbox."""
|
||||||
|
fake_media = tmp_path / "media"
|
||||||
|
fake_media.mkdir()
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"nanobot.agent.tools.sandbox.get_media_dir",
|
||||||
|
lambda: fake_media,
|
||||||
|
)
|
||||||
|
ws = str(tmp_path / "project")
|
||||||
|
result = wrap_command("bwrap", "ls", ws, ws)
|
||||||
|
tokens = _parse(result)
|
||||||
|
|
||||||
|
try_indices = [i for i, t in enumerate(tokens) if t == "--ro-bind-try"]
|
||||||
|
try_pairs = {(tokens[i + 1], tokens[i + 2]) for i in try_indices}
|
||||||
|
assert (str(fake_media), str(fake_media)) in try_pairs
|
||||||
|
|
||||||
|
|
||||||
class TestUnknownBackend:
|
class TestUnknownBackend:
|
||||||
def test_raises_value_error(self, tmp_path):
|
def test_raises_value_error(self, tmp_path):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user