From 64acf4e1a32e0f932ef831c28e039e5b8907b3d9 Mon Sep 17 00:00:00 2001 From: Paulo Date: Sun, 4 Oct 2026 17:14:57 +0200 Subject: [PATCH] Remove SandboxSettings --- backend/druks/harnesses/base.py | 5 -- backend/druks/harnesses/claude.py | 16 +--- backend/druks/harnesses/codex.py | 20 ++--- backend/druks/harnesses/datastructures.py | 35 -------- backend/druks/harnesses/opencode.py | 6 -- backend/druks/harnesses/pi.py | 6 -- backend/druks/sandbox/host.py | 2 - backend/tests/test_harness_auth.py | 83 ++++++------------- backend/tests/test_harness_reasoning_flags.py | 20 +---- backend/tests/test_manifest.py | 2 - backend/tests/test_mcp_servers.py | 26 +----- backend/tests/test_opencode.py | 13 --- backend/tests/test_pi.py | 8 -- backend/tests/test_sandboxed_harness.py | 15 ++-- 14 files changed, 48 insertions(+), 209 deletions(-) diff --git a/backend/druks/harnesses/base.py b/backend/druks/harnesses/base.py index d4e71235a..8edf58ab9 100644 --- a/backend/druks/harnesses/base.py +++ b/backend/druks/harnesses/base.py @@ -21,7 +21,6 @@ from .datastructures import ( AgentInvocation, HarnessRunResult, - SandboxSettings, ) from .providers import Provider, get_provider, is_registered @@ -67,14 +66,10 @@ def __init__( model: str | None, fast_mode: bool, effort: str | None, - sandbox: SandboxSettings | None = None, ) -> None: self.model = model self.fast_mode = fast_mode self.effort = effort - # Optional only so argv-shape unit tests can build the harness without a - # sandbox-configured Settings; every real run needs it and raises when None. - self.sandbox = sandbox @abstractmethod async def build_invocation(self, session: AsyncSession, **kwargs: object) -> AgentInvocation: diff --git a/backend/druks/harnesses/claude.py b/backend/druks/harnesses/claude.py index 3d277eca6..b73c00b4f 100644 --- a/backend/druks/harnesses/claude.py +++ b/backend/druks/harnesses/claude.py @@ -19,13 +19,13 @@ from druks.sandbox.layout import get_runs_root from druks.sandbox.models import SecretRef from druks.secrets.models import VaultSecret +from druks.settings import load_settings from druks.skills.models import Skill from . import exceptions from .artifacts import call_dir, write_cost from .base import Harness from .constants import CLAUDE_DISALLOWED_TOOLS -from .datastructures import SandboxSettings from .providers import AnthropicProvider logger = logging.getLogger(__name__) @@ -113,12 +113,6 @@ async def build_invocation( identity: dict | None = None, timeout: int = Harness.default_timeout, ) -> AgentInvocation: - if not self.sandbox: - raise exceptions.HarnessError( - "claude harness requires sandbox settings — set sandbox.service_url and " - "related TOML settings.", - ) - in_vm_run_dir = f"{get_runs_root(ssh_username)}/{run_id}" in_vm_debug = f"{in_vm_run_dir}/debug.log" in_vm_session = f"{in_vm_run_dir}/session.jsonl" @@ -168,7 +162,6 @@ async def build_invocation( stdin=prompt.encode("utf-8"), credentials=await _get_credentials( session, - self.sandbox, include_plugins=include_plugins, skills=skills, ), @@ -241,7 +234,6 @@ def _command_args(self) -> tuple[str, ...]: async def _get_credentials( session: AsyncSession, - sandbox: SandboxSettings, *, include_plugins: bool = True, skills: tuple[str, ...] = (), @@ -251,7 +243,8 @@ async def _get_credentials( placeholder for its token or key. ``include_plugins=False`` skips the operator's plugin state, for prompts that use no MCP server and would otherwise die on a misconfigured plugin.""" - config_dir = sandbox.harness_config_root / ClaudeHarness.name + settings = load_settings() + config_dir = settings.harness_config_root / ClaudeHarness.name home: list[HomeFile | HomeCopy] = [] claude_json = config_dir / ".claude.json" if claude_json.is_file(): @@ -274,11 +267,10 @@ async def _get_credentials( HomeCopy(".claude/plugins/marketplaces", plugins / "marketplaces"), HomeCopy(".claude/plugins/cache", plugins / "cache"), ] - skills_dir = sandbox.skills_dir or config_dir / "skills" home.append( HomeCopy( ".claude/skills", - skills_dir, + settings.skills_dir, excludes=await Skill.delivery_excludes(session, skills), ) ) diff --git a/backend/druks/harnesses/codex.py b/backend/druks/harnesses/codex.py index c0e7a69e4..e72f4108b 100644 --- a/backend/druks/harnesses/codex.py +++ b/backend/druks/harnesses/codex.py @@ -24,14 +24,13 @@ from druks.sandbox.layout import get_runs_root, get_work_root from druks.sandbox.models import SecretRef from druks.secrets.models import VaultSecret +from druks.settings import load_settings from druks.skills.models import Skill from .artifacts import write_cost from .base import Harness -from .datastructures import SandboxSettings from .exceptions import ( HarnessAuthError, - HarnessError, HarnessOverloadedError, HarnessRateLimitError, HarnessSpendLimitError, @@ -466,13 +465,6 @@ async def build_invocation( identity: dict | None = None, timeout: int = Harness.default_timeout, ) -> AgentInvocation: - sandbox = self.sandbox - if not sandbox: - raise HarnessError( - f"{self.name} harness requires sandbox settings — set " - "sandbox.service_url and related TOML settings.", - ) - cmd = self._build_codex_wrapper( ssh_username=ssh_username, schema=schema, @@ -491,7 +483,7 @@ async def build_invocation( name=self.name, args=tuple(cmd), stdin=_with_final_message_note(prompt).encode("utf-8"), - credentials=await self._get_credentials(session, sandbox, skills=skills), + credentials=await self._get_credentials(session, skills=skills), env=extra_env, extra_artifact_filenames=("output.json", "session.jsonl"), ) @@ -566,17 +558,17 @@ def _prompt_flags(self) -> tuple[str, ...]: return args async def _get_credentials( - self, session: AsyncSession, sandbox: SandboxSettings, *, skills: tuple[str, ...] = () + self, session: AsyncSession, *, skills: tuple[str, ...] = () ) -> Credentials: - config_dir = sandbox.harness_config_root / self.name - skills_dir = sandbox.skills_dir or config_dir / "skills" + settings = load_settings() + config_dir = settings.harness_config_root / self.name return Credentials( home=( HomeCopy(".codex/config.toml", config_dir / "config.toml"), HomeCopy(".codex/AGENTS.md", config_dir / "AGENTS.md"), HomeCopy( ".codex/skills", - skills_dir, + settings.skills_dir, excludes=await Skill.delivery_excludes(session, skills), ), ) diff --git a/backend/druks/harnesses/datastructures.py b/backend/druks/harnesses/datastructures.py index 53e047e47..78f21867e 100644 --- a/backend/druks/harnesses/datastructures.py +++ b/backend/druks/harnesses/datastructures.py @@ -1,18 +1,14 @@ from collections.abc import Sequence from dataclasses import dataclass, field from datetime import datetime -from pathlib import Path from typing import Literal, Self -from pydantic import SecretStr - # Execution-side types live with the executor; re-exported here # because the harness API speaks them. from druks.sandbox.datastructures import ( # noqa: F401 AgentInvocation, HarnessRunResult, ) -from druks.settings import Settings Billing = Literal["subscription", "api_key"] @@ -98,34 +94,3 @@ class ParsedUsage: # should render "unmetered" rather than a quota that never moves. unlimited: bool = False raw: str = field(default="", repr=False) - - -@dataclass(frozen=True) -class SandboxSettings: - service_url: str - service_token: SecretStr - service_timeout: float - image: str - # Each harness owns one directory under this root. Missing files are not - # copied into the sandbox. - harness_config_root: Path - # Canonical shared-skills dir pushed into both ~/.claude/skills and - # ~/.codex/skills in the VM. ``None`` => per-CLI fallback (the skills - # subdir of each home). - skills_dir: Path | None = None - - @classmethod - def from_settings(cls, settings: Settings) -> Self: - return cls( - service_url=settings.sandbox.service_url, - service_token=settings.sandbox.service_token, - service_timeout=settings.sandbox.timeout, - image=settings.sandbox.image, - harness_config_root=settings.harness_config_root, - skills_dir=settings.skills_dir, - ) - - @classmethod - def maybe_from_settings(cls, settings: Settings) -> Self | None: - if settings.sandbox.service_url: - return cls.from_settings(settings) diff --git a/backend/druks/harnesses/opencode.py b/backend/druks/harnesses/opencode.py index 23d91293f..7007655dd 100644 --- a/backend/druks/harnesses/opencode.py +++ b/backend/druks/harnesses/opencode.py @@ -97,12 +97,6 @@ async def build_invocation( identity: dict | None = None, timeout: int = Harness.default_timeout, ) -> AgentInvocation: - if not self.sandbox: - raise exceptions.HarnessError( - "opencode harness requires sandbox settings — set sandbox.service_url and " - "related TOML settings.", - ) - mcp = {} for server in mcp_servers: headers = dict(server.headers) diff --git a/backend/druks/harnesses/pi.py b/backend/druks/harnesses/pi.py index 044d3efc9..6f7aaa74c 100644 --- a/backend/druks/harnesses/pi.py +++ b/backend/druks/harnesses/pi.py @@ -56,12 +56,6 @@ async def build_invocation( identity: dict | None = None, timeout: int = Harness.default_timeout, ) -> AgentInvocation: - if not self.sandbox: - raise exceptions.HarnessError( - f"{self.name} harness requires sandbox settings — set " - "sandbox.service_url and related TOML settings.", - ) - model = self.model_id provider = self.model.partition("/")[0] in_vm_run_dir = f"{get_runs_root(ssh_username)}/{run_id}" diff --git a/backend/druks/sandbox/host.py b/backend/druks/sandbox/host.py index cee7171e1..994be0992 100644 --- a/backend/druks/sandbox/host.py +++ b/backend/druks/sandbox/host.py @@ -17,7 +17,6 @@ from druks.core.utils.time import ensure_utc from druks.durable.enums import AgentCallStatus from druks.harnesses.artifacts import persist_manifest, persist_prompt, read_cost -from druks.harnesses.datastructures import SandboxSettings from druks.harnesses.exceptions import ( HarnessError, HarnessFirstByteTimeoutError, @@ -231,7 +230,6 @@ async def run_agent( model=model, fast_mode=config.fast_mode, effort=config.effort, - sandbox=SandboxSettings.maybe_from_settings(load_settings()), ) # Names the artifact subdir and is the AgentCall.id — supplied by the diff --git a/backend/tests/test_harness_auth.py b/backend/tests/test_harness_auth.py index 03d7d8471..2ec7c9aca 100644 --- a/backend/tests/test_harness_auth.py +++ b/backend/tests/test_harness_auth.py @@ -2,6 +2,7 @@ import json import shlex from pathlib import Path +from types import SimpleNamespace from unittest.mock import AsyncMock import pytest @@ -11,7 +12,6 @@ from druks.db import db_session from druks.harnesses.claude import ClaudeHarness, _get_credentials from druks.harnesses.codex import CodexHarness -from druks.harnesses.datastructures import SandboxSettings from druks.harnesses.exceptions import AgentConfigError, HarnessNotConnectedError from druks.harnesses.opencode import OpenCodeHarness from druks.harnesses.pi import PiHarness @@ -23,6 +23,17 @@ from druks_field_notes.workflows import Summarize +@pytest.fixture +def config_root(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> Path: + settings = SimpleNamespace( + harness_config_root=tmp_path / "harnesses", + skills_dir=tmp_path / "skills", + ) + monkeypatch.setattr("druks.harnesses.claude.load_settings", lambda: settings) + monkeypatch.setattr("druks.harnesses.codex.load_settings", lambda: settings) + return settings.harness_config_root + + async def _seed_claude( *, provider_email="op@example.com", @@ -39,29 +50,19 @@ async def _seed_claude( ) -async def test_claude_bundle_carries_no_credential_file(druks_db): +async def test_claude_bundle_carries_no_credential_file(druks_db, config_root): """The sandbox holds a placeholder for the token. No file carries it.""" await _seed_claude(access="live", refresh="R0") - sandbox = SandboxSettings( - service_url="x", - service_token="x", - service_timeout=30.0, - image="x", - harness_config_root=Path("/harnesses"), - ) - bundle = await _get_credentials(db_session(), sandbox) + bundle = await _get_credentials(db_session()) assert not any(type(entry) is HomeFile for entry in bundle.home) - assert bundle.home[0] == HomeCopy( - ".claude/settings.json", Path("/harnesses/claude/settings.json") - ) + assert bundle.home[0] == HomeCopy(".claude/settings.json", config_root / "claude/settings.json") async def test_the_operators_claude_config_reaches_the_box_without_its_mcp_servers( - druks_db, tmp_path + druks_db, config_root ): # Druks delivers every server it manages; a copied entry could carry a # token the vault never saw. - config_root = tmp_path / "harnesses" (config_root / "claude").mkdir(parents=True) (config_root / "claude" / ".claude.json").write_text( json.dumps( @@ -71,15 +72,8 @@ async def test_the_operators_claude_config_reaches_the_box_without_its_mcp_serve } ) ) - sandbox = SandboxSettings( - service_url="x", - service_token="x", - service_timeout=30.0, - image="x", - harness_config_root=config_root, - ) - bundle = await _get_credentials(db_session(), sandbox) + bundle = await _get_credentials(db_session()) [config] = [entry for entry in bundle.home if entry.path == ".claude.json"] assert json.loads(config.content) == {"theme": "dark"} @@ -110,23 +104,15 @@ async def _seed_codex() -> VaultSecret: ) -async def test_credentials_builders_read_their_harness_config_directories(druks_db): - config_root = Path("/harnesses") - sandbox = SandboxSettings( - service_url="x", - service_token="x", - service_timeout=30.0, - image="x", - harness_config_root=config_root, - ) - - claude_bundle = await _get_credentials(db_session(), sandbox) +async def test_credentials_builders_read_their_harness_config_directories( + druks_db, config_root, tmp_path +): + claude_bundle = await _get_credentials(db_session()) codex_bundle = await CodexHarness( model=CodexHarness.default_model, fast_mode=False, effort=None, - sandbox=sandbox, - )._get_credentials(db_session(), sandbox) + )._get_credentials(db_session()) # No credential file: each CLI reads a placeholder the box holds. assert not any(type(entry) is HomeFile for entry in (*claude_bundle.home, *codex_bundle.home)) @@ -155,13 +141,13 @@ async def test_credentials_builders_read_their_harness_config_directories(druks_ assert HomeCopy(".claude/plugins/cache", config_root / "claude/plugins/cache") in ( claude_bundle.home ) - assert claude_bundle.home[-1].source == config_root / "claude/skills" + assert claude_bundle.home[-1].source == tmp_path / "skills" assert HomeCopy(".codex/config.toml", config_root / "codex/config.toml") in codex_bundle.home # MCP credentials are box entries; a copied credentials file would carry a # second, unmanaged set. assert not any(file.path == ".codex/.credentials.json" for file in codex_bundle.home) assert HomeCopy(".codex/AGENTS.md", config_root / "codex/AGENTS.md") in codex_bundle.home - assert codex_bundle.home[-1].source == config_root / "codex/skills" + assert codex_bundle.home[-1].source == tmp_path / "skills" @pytest.mark.parametrize( @@ -175,24 +161,16 @@ async def test_credentials_builders_read_their_harness_config_directories(druks_ ) @pytest.mark.parametrize("config_exists", [False, True]) async def test_config_delivery_does_not_copy_host_provider_credentials( - druks_db, tmp_path, harness, config_name, auth_name, config_exists + druks_db, config_root, harness, config_name, auth_name, config_exists ): - config_root = tmp_path / "harnesses" config_dir = config_root / harness.name if config_exists: config_dir.mkdir(parents=True) (config_dir / config_name).write_text("") (config_dir / auth_name).write_text('{"token": "host-token"}') - sandbox = SandboxSettings( - service_url="x", - service_token="x", - service_timeout=30.0, - image="x", - harness_config_root=config_root, - ) invocation = await harness( - model=harness.default_model, fast_mode=False, effort=None, sandbox=sandbox + model=harness.default_model, fast_mode=False, effort=None ).build_invocation( db_session(), prompt="hello", @@ -245,16 +223,9 @@ async def test_a_codex_subscription_binds_a_custom_entry_on_chatgpt(druks_db): async def test_the_codex_wrapper_writes_its_login_around_the_placeholder(druks_db): subscription = await _seed_codex() tokens = subscription.secrets["tokens"] - sandbox = SandboxSettings( - service_url="x", - service_token="x", - service_timeout=30.0, - image="x", - harness_config_root=Path("/harnesses"), - ) invocation = await CodexHarness( - model=CodexHarness.default_model, fast_mode=False, effort=None, sandbox=sandbox + model=CodexHarness.default_model, fast_mode=False, effort=None ).build_invocation( db_session(), prompt="hello", diff --git a/backend/tests/test_harness_reasoning_flags.py b/backend/tests/test_harness_reasoning_flags.py index 233c095d6..51c6b35f1 100644 --- a/backend/tests/test_harness_reasoning_flags.py +++ b/backend/tests/test_harness_reasoning_flags.py @@ -1,27 +1,15 @@ import json import shlex -from pathlib import Path from drukbox_sdk import Secret from druks.db import db_session from druks.harnesses.claude import ClaudeHarness from druks.harnesses.codex import CodexHarness -from druks.harnesses.datastructures import SandboxSettings from druks.sandbox.datastructures import McpServer _CODEX_MODEL = CodexHarness.default_model -def _sandbox_config(): - return SandboxSettings( - service_url="https://sb.test", - service_token="t", - service_timeout=30.0, - image="img", - harness_config_root=Path("/harnesses"), - ) - - async def test_claude_build_invocation_carries_every_flag(): """The Claude invocation carries the complete supported flag set.""" schema = {"type": "object"} @@ -30,7 +18,6 @@ async def test_claude_build_invocation_carries_every_flag(): model="anthropic/claude-x", fast_mode=True, effort="high", - sandbox=_sandbox_config(), ).build_invocation( db_session(), identity={"email": "op@example.com"}, @@ -87,7 +74,6 @@ async def test_codex_build_invocation_carries_every_flag(): model=_CODEX_MODEL, fast_mode=True, effort="high", - sandbox=_sandbox_config(), ).build_invocation( db_session(), identity={"email": "op@example.com", "account_id": "acc-1"}, @@ -149,7 +135,7 @@ async def test_claude_reads_its_key_from_a_placeholder_in_the_vm(): ) } inv = await ClaudeHarness( - model="anthropic/claude-x", fast_mode=False, effort=None, sandbox=_sandbox_config() + model="anthropic/claude-x", fast_mode=False, effort=None ).build_invocation( db_session(), prompt="hello", @@ -175,9 +161,7 @@ async def test_codex_reads_its_key_from_a_placeholder_in_the_vm(): auth_prefix="Bearer ", ) } - inv = await CodexHarness( - model=_CODEX_MODEL, fast_mode=False, effort=None, sandbox=_sandbox_config() - ).build_invocation( + inv = await CodexHarness(model=_CODEX_MODEL, fast_mode=False, effort=None).build_invocation( db_session(), prompt="hello", schema={"type": "object"}, diff --git a/backend/tests/test_manifest.py b/backend/tests/test_manifest.py index 28db182fa..15965ccf9 100644 --- a/backend/tests/test_manifest.py +++ b/backend/tests/test_manifest.py @@ -26,8 +26,6 @@ async def _build( mcp_servers: tuple[McpServer, ...] = (), skills: tuple[str, ...] = (), ) -> dict: - # get_manifest never touches the live sandbox, so the harness builds - # without sandbox settings — the same shape argv unit tests use. harness = harness or ClaudeHarness( model="anthropic/claude-opus-4-8", fast_mode=False, effort=None ) diff --git a/backend/tests/test_mcp_servers.py b/backend/tests/test_mcp_servers.py index cd6d70ef4..2810298a2 100644 --- a/backend/tests/test_mcp_servers.py +++ b/backend/tests/test_mcp_servers.py @@ -1,5 +1,4 @@ import json -from pathlib import Path from types import SimpleNamespace import pytest @@ -9,7 +8,6 @@ from druks.db import db_session from druks.harnesses.claude import ClaudeHarness from druks.harnesses.codex import CodexHarness -from druks.harnesses.datastructures import SandboxSettings from druks.mcp.catalog import load_mcp_catalog from druks.mcp.constants import BEARER_HEADER, DRUKS_SERVER_NAME from druks.mcp.exceptions import ( @@ -36,16 +34,6 @@ _BEARER = {"Authorization": f"Bearer {_TOKEN}"} -def _sandbox_config() -> SandboxSettings: - return SandboxSettings( - service_url="https://sb.test", - service_token="t", - service_timeout=30.0, - image="img", - harness_config_root=Path("/harnesses"), - ) - - async def _servers() -> tuple: # The enabled servers as the harness names them; their credentials are box # entries, never env. @@ -247,9 +235,7 @@ async def test_enabled_server_reaches_both_harness_configs_without_token(druks_d servers = await _servers() claude_config = " ".join( - ClaudeHarness( - model="claude-x", fast_mode=False, effort=None, sandbox=_sandbox_config() - )._mcp_flags(servers) + ClaudeHarness(model="claude-x", fast_mode=False, effort=None)._mcp_flags(servers) ) assert _LINEAR_URL in claude_config assert "MCP_LINEAR_HEADER_0" in claude_config @@ -260,7 +246,6 @@ async def test_enabled_server_reaches_both_harness_configs_without_token(druks_d model=CodexHarness.default_model, fast_mode=False, effort=None, - sandbox=_sandbox_config(), )._mcp_flags(servers) ) assert _LINEAR_URL in codex_config @@ -338,9 +323,7 @@ async def test_two_header_server_emits_both_headers_in_each_harness_config(druks servers = await _servers() header_env_var = servers[0].env_headers["X-Api-Key"] - claude_flags = ClaudeHarness( - model="claude-x", fast_mode=False, effort=None, sandbox=_sandbox_config() - )._mcp_flags(servers) + claude_flags = ClaudeHarness(model="claude-x", fast_mode=False, effort=None)._mcp_flags(servers) headers = json.loads(claude_flags[1])["mcpServers"]["grafana"]["headers"] assert headers == { "X-Grafana-URL": "https://acme.grafana.net", @@ -353,7 +336,6 @@ async def test_two_header_server_emits_both_headers_in_each_harness_config(druks model=CodexHarness.default_model, fast_mode=False, effort=None, - sandbox=_sandbox_config(), )._mcp_flags(servers) ) assert 'http_headers."X-Grafana-URL"="https://acme.grafana.net"' in codex_config @@ -375,9 +357,7 @@ async def test_secret_and_declared_headers_combine_on_one_server(druks_db): servers = await _servers() - claude_flags = ClaudeHarness( - model="claude-x", fast_mode=False, effort=None, sandbox=_sandbox_config() - )._mcp_flags(servers) + claude_flags = ClaudeHarness(model="claude-x", fast_mode=False, effort=None)._mcp_flags(servers) headers = json.loads(claude_flags[1])["mcpServers"]["acme"]["headers"] assert headers == { "Authorization": "${MCP_ACME_HEADER_0}", diff --git a/backend/tests/test_opencode.py b/backend/tests/test_opencode.py index 4df6471e4..b6b6748f8 100644 --- a/backend/tests/test_opencode.py +++ b/backend/tests/test_opencode.py @@ -4,7 +4,6 @@ import pytest from druks.db import db_session -from druks.harnesses.datastructures import SandboxSettings from druks.harnesses.exceptions import ( HarnessError, HarnessInvalidOutputError, @@ -26,22 +25,11 @@ class _Contract(BaseModel): count: int -def _sandbox_config() -> SandboxSettings: - return SandboxSettings( - service_url="https://sandbox.test", - service_token="token", - service_timeout=30.0, - image="image", - harness_config_root=Path("/harnesses"), - ) - - def _harness() -> OpenCodeHarness: return OpenCodeHarness( model=_MODEL, fast_mode=False, effort=None, - sandbox=_sandbox_config(), ) @@ -154,7 +142,6 @@ async def test_third_party_invocation_keeps_provider_key_and_model_namespace() - model="openrouter/anthropic/claude-sonnet-4", fast_mode=False, effort=None, - sandbox=_sandbox_config(), ) invocation = await harness.build_invocation( diff --git a/backend/tests/test_pi.py b/backend/tests/test_pi.py index 166b481bb..114ee9a4c 100644 --- a/backend/tests/test_pi.py +++ b/backend/tests/test_pi.py @@ -6,7 +6,6 @@ import pytest from drukbox_sdk import Secret from druks.db import db_session -from druks.harnesses.datastructures import SandboxSettings from druks.harnesses.exceptions import ( HarnessAuthError, HarnessError, @@ -38,13 +37,6 @@ def _harness(*, effort: str | None = "high") -> PiHarness: model=PiHarness.default_model, fast_mode=False, effort=effort, - sandbox=SandboxSettings( - service_url="https://sandbox.test", - service_token="token", - service_timeout=30.0, - image="image", - harness_config_root=Path("/harnesses"), - ), ) diff --git a/backend/tests/test_sandboxed_harness.py b/backend/tests/test_sandboxed_harness.py index b2ad45aea..2c76381e1 100644 --- a/backend/tests/test_sandboxed_harness.py +++ b/backend/tests/test_sandboxed_harness.py @@ -591,11 +591,10 @@ async def test_claude_api_key_stays_on_the_server( sandbox.run_prompt = functools.partial(Host.run_prompt, sandbox) sandbox._exec = functools.partial(Host._exec, sandbox) settings = SimpleNamespace( - sandbox=SimpleNamespace(service_url="x", service_token="x", timeout=30.0, image="x"), harness_config_root=tmp_path / "harnesses", - skills_dir=None, + skills_dir=tmp_path / "skills", ) - monkeypatch.setattr("druks.sandbox.host.load_settings", lambda: settings) + monkeypatch.setattr("druks.harnesses.claude.load_settings", lambda: settings) result = await Host.run_agent( sandbox, @@ -650,11 +649,10 @@ async def test_claude_subscription_token_stays_on_the_server( sandbox.run_prompt = functools.partial(Host.run_prompt, sandbox) sandbox._exec = functools.partial(Host._exec, sandbox) settings = SimpleNamespace( - sandbox=SimpleNamespace(service_url="x", service_token="x", timeout=30.0, image="x"), harness_config_root=tmp_path / "harnesses", - skills_dir=None, + skills_dir=tmp_path / "skills", ) - monkeypatch.setattr("druks.sandbox.host.load_settings", lambda: settings) + monkeypatch.setattr("druks.harnesses.claude.load_settings", lambda: settings) result = await Host.run_agent( sandbox, @@ -707,11 +705,10 @@ async def test_codex_subscription_token_stays_on_the_server( sandbox.run_prompt = functools.partial(Host.run_prompt, sandbox) sandbox._exec = functools.partial(Host._exec, sandbox) settings = SimpleNamespace( - sandbox=SimpleNamespace(service_url="x", service_token="x", timeout=30.0, image="x"), harness_config_root=tmp_path / "harnesses", - skills_dir=None, + skills_dir=tmp_path / "skills", ) - monkeypatch.setattr("druks.sandbox.host.load_settings", lambda: settings) + monkeypatch.setattr("druks.harnesses.codex.load_settings", lambda: settings) result = await Host.run_agent( sandbox,