fix: execute local reins through the sandbox owner
Some checks failed
ci / validate (push) Has been cancelled

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
This commit is contained in:
tegwick 2026-09-05 19:16:22 +02:00
parent 92392f75f1
commit 63a7f9f160
14 changed files with 463 additions and 81 deletions

View file

@ -1,6 +1,8 @@
from datetime import UTC, datetime
from unittest.mock import MagicMock, patch
import pytest
from sandboxer.models import Reachability, SandboxState, SandboxStatus
from glas_harness.contract import (
@ -14,6 +16,7 @@ from glas_harness.contract import (
)
from glas_harness.gateway import run_execution, run_task_through_rein
from glas_harness.profiles import ProfileCatalog
from glas_harness.transport import transport_from_sandbox
PROFILE = "harness.agent-dev-local@1.0.0"
@ -127,6 +130,81 @@ def test_run_execution_creates_and_destroys_sandbox() -> None:
assert result.tool_output == "sensitive direct output"
@pytest.mark.parametrize("request_id", ["exact-request", None])
def test_owner_commands_preserve_create_identity_routes_and_timeout(request_id):
manager = MagicMock()
manager.create.return_value = _fake_status()
manager.execute.return_value = MagicMock(
timed_out=False, output_truncated=False, exit_code=0, stdout="", stderr=""
)
catalog = _catalog_with_readiness()
profile, _ = catalog.resolve(PROFILE)
refs = ["proof-route-a", "proof-route-b"]
catalog.profiles()[(profile.id, profile.version)] = profile.model_copy(update={
"credential_route_refs": refs,
"limits": profile.limits.model_copy(update={"timeout_seconds": 7}),
})
class OwnerRein(_FakeRein):
def start_session(self, profile, inputs, sandbox):
assert "_owner_execute" not in sandbox.model_dump()
transport = transport_from_sandbox(sandbox)
transport.run(["printf", "%s", "non-secret"], timeout=30)
path = transport.write_task_file({"title": "private prompt"})
transport.remove_file(path)
return super().start_session(profile, inputs, sandbox)
request = _request().model_copy(update={
"request_id": request_id, "actor": "atm", "project": "exact-project"
})
result = run_execution(request, catalog=catalog, rein=OwnerRein(), manager=manager)
assert result.ok
create_consumer = manager.create.call_args.args[0].consumer
assert create_consumer.actor.value == "atm"
assert create_consumer.project == "exact-project"
assert create_consumer.run_id == result.evidence.request_id
assert create_consumer.session_id is None
assert manager.execute.call_count == 3
for call in manager.execute.call_args_list:
sandbox_id, command = call.args
assert sandbox_id == "sbx1"
assert command.consumer == create_consumer
assert command.credential_route_refs == refs
assert command.timeout_seconds == 7
writer = manager.execute.call_args_list[1].args[1]
assert writer.stdin_text == '{"title": "private prompt"}'
assert "private prompt" not in str(writer.command)
manager.destroy.assert_called_once_with("sbx1")
@pytest.mark.parametrize("failure", ["refused", "timeout", "truncated", "write"])
def test_owner_session_failure_still_destroys_sandbox(failure):
from glas_harness.reins.rein_aharness import ReinAharness
manager = MagicMock()
manager.create.return_value = _fake_status()
good = MagicMock(timed_out=False, output_truncated=False, exit_code=0,
stdout="head-before", stderr="")
if failure == "refused":
manager.execute.side_effect = PermissionError("owner denied execution")
elif failure == "write":
manager.execute.side_effect = [good, MagicMock(
timed_out=False, output_truncated=False, exit_code=1,
stdout="", stderr="task write refused",
)]
else:
manager.execute.return_value = MagicMock(
timed_out=failure == "timeout", output_truncated=failure == "truncated"
)
with patch("glas_harness.transport.subprocess.run") as host_run:
result = run_execution(_request(), catalog=_catalog_with_readiness(),
rein=ReinAharness(), manager=manager)
assert not result.ok
assert result.evidence.failure_stage == "session_start"
manager.destroy.assert_called_once_with("sbx1")
host_run.assert_not_called()
def test_run_execution_normalizes_execution_failure_and_tears_down() -> None:
manager = MagicMock()
manager.create.return_value = _fake_status()