mirror of
https://github.com/priyanshujain/messageboardbench.git
synced 2026-10-02 11:07:07 +00:00
139 lines
5.7 KiB
Python
139 lines
5.7 KiB
Python
from pathlib import Path
|
|
import errno
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from messageboardbench.shared import (
|
|
TEAM_COMPOSE, prepare_team_directory, snapshot_team_directory,
|
|
validate_team_directory, render_team_compose,
|
|
)
|
|
|
|
|
|
def test_creates_shared_board_and_dedicated_agent_folders(tmp_path):
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1", "agent-2"])
|
|
assert team == tmp_path / "shared" / "team-1"
|
|
assert (team / "board").is_dir()
|
|
assert (team / "agents" / "agent-2").is_dir()
|
|
with pytest.raises(FileExistsError):
|
|
prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
|
|
|
|
@pytest.mark.parametrize("name", ["../outside", "/workspace", "a/b", "a b", "", "."])
|
|
def test_rejects_unsafe_team_names(tmp_path, name):
|
|
with pytest.raises(ValueError):
|
|
prepare_team_directory(tmp_path, name, ["agent-1"])
|
|
|
|
|
|
def test_rejects_mount_of_run_root_and_shared_symlink(tmp_path):
|
|
with pytest.raises(ValueError):
|
|
validate_team_directory(tmp_path, tmp_path)
|
|
outside = tmp_path / "outside"
|
|
outside.mkdir()
|
|
(tmp_path / "shared").symlink_to(outside, target_is_directory=True)
|
|
with pytest.raises(ValueError):
|
|
prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
|
|
|
|
def test_snapshot_skips_links_to_logs_and_handles_binary_and_large_files(tmp_path):
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
secret = tmp_path / "researcher-log.txt"
|
|
secret.write_text("private provenance")
|
|
(team / "board" / "log-link").symlink_to(secret)
|
|
(team / "board" / "directory-link").symlink_to(tmp_path, target_is_directory=True)
|
|
(team / "board" / "note").write_bytes(b"abcdef\xff")
|
|
snapshot = snapshot_team_directory(team, max_bytes=4)
|
|
assert snapshot["board/log-link"] == {"kind": "symlink", "skipped": True}
|
|
assert snapshot["board/directory-link"]["skipped"]
|
|
assert snapshot["board/note"]["content"] == "abcd"
|
|
assert snapshot["board/note"]["truncated"]
|
|
assert "private provenance" not in str(snapshot)
|
|
|
|
|
|
def test_snapshot_limit_and_missing_root_are_errors(tmp_path):
|
|
with pytest.raises(FileNotFoundError):
|
|
snapshot_team_directory(tmp_path / "absent")
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
with pytest.raises(ValueError, match="entry limit"):
|
|
snapshot_team_directory(team, max_files=1)
|
|
|
|
|
|
def test_production_compose_mount_is_explicit_and_local_workdir_unshared():
|
|
import yaml
|
|
config = yaml.safe_load(TEAM_COMPOSE.read_text())
|
|
service = config["services"]["default"]
|
|
assert service["working_dir"] == "/workspace"
|
|
assert service["network_mode"] == "none"
|
|
assert len(service["volumes"]) == 1
|
|
mount = service["volumes"][0]
|
|
assert mount["target"] == "/workspace/scratch"
|
|
assert "SAMPLE_METADATA_TEAM_DIR" in mount["source"]
|
|
assert mount["bind"]["create_host_path"] is False
|
|
|
|
|
|
def test_installed_inspect_resolves_team_metadata_for_production_compose(tmp_path):
|
|
from inspect_ai.util._sandbox.docker.docker import resolve_config_environment
|
|
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
resolved = resolve_config_environment(str(TEAM_COMPOSE), {"team_dir": str(team)})
|
|
assert resolved is not None
|
|
assert resolved.env["SAMPLE_METADATA_TEAM_DIR"] == str(team)
|
|
|
|
|
|
def test_snapshot_records_file_deleted_between_listing_and_stat(tmp_path, monkeypatch):
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
(team / "board" / "temporary").write_text("draft")
|
|
original_stat = os.stat
|
|
|
|
def disappearing_stat(path, *args, **kwargs):
|
|
if path == "temporary" and "dir_fd" in kwargs:
|
|
raise FileNotFoundError(errno.ENOENT, "concurrently renamed", path)
|
|
return original_stat(path, *args, **kwargs)
|
|
|
|
monkeypatch.setattr(os, "stat", disappearing_stat)
|
|
snapshot = snapshot_team_directory(team)
|
|
assert snapshot["board/temporary"]["kind"] == "transient"
|
|
assert snapshot["board/temporary"]["errno"] == errno.ENOENT
|
|
|
|
|
|
def test_snapshot_records_symlink_substituted_between_stat_and_open(tmp_path, monkeypatch):
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
note = team / "board" / "note"
|
|
note.write_text("draft")
|
|
secret = tmp_path / "private-log"
|
|
secret.write_text("private provenance")
|
|
original_open = os.open
|
|
|
|
def replaced_open(path, flags, *args, **kwargs):
|
|
if path == "note" and "dir_fd" in kwargs:
|
|
note.unlink()
|
|
note.symlink_to(secret)
|
|
return original_open(path, flags, *args, **kwargs)
|
|
|
|
monkeypatch.setattr(os, "open", replaced_open)
|
|
snapshot = snapshot_team_directory(team)
|
|
assert snapshot["board/note"]["kind"] == "transient"
|
|
assert "private provenance" not in str(snapshot)
|
|
|
|
|
|
def test_rendered_compose_needs_no_sample_metadata_at_task_initialization(tmp_path):
|
|
import json
|
|
from inspect_ai.util._sandbox.docker.docker import resolve_config_environment
|
|
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
path = render_team_compose(team, tmp_path / "config" / "team.compose.json")
|
|
assert "${" not in path.read_text()
|
|
config = json.loads(path.read_text())
|
|
assert config["services"]["default"]["volumes"][0]["source"] == str(team)
|
|
assert resolve_config_environment(str(path), {}).env == {}
|
|
assert render_team_compose(team, path) == path
|
|
other = prepare_team_directory(tmp_path, "team-2", ["agent-1"])
|
|
with pytest.raises(ValueError, match="differs"):
|
|
render_team_compose(other, path)
|
|
|
|
|
|
def test_rendered_compose_cannot_be_written_into_agent_mount(tmp_path):
|
|
team = prepare_team_directory(tmp_path, "team-1", ["agent-1"])
|
|
with pytest.raises(ValueError, match="outside"):
|
|
render_team_compose(team, team / "compose.json")
|