The OS lanes are marker-driven: list_os_marked_tests.py picks the files
a lane imports from their platforms() specs and the lane selects with
-m platforms. A test gated with skipif(sys.platform != "win32") is
therefore never imported on the Windows lane and skipped everywhere else
— it runs on no host. skipif(sys.platform == "win32") tests were merely
invisible to the lane bookkeeping, but the rule the tree now follows is
one host marker, never a bare skipif.
Mechanical mapping, semantics preserved: skip-on-Windows → "posix",
skip-off-Windows → "windows", skip-off-Linux → "linux", skip-on-macOS →
"not macos". The former skip reasons stay as trailing comments. A
non-host condition (os.geteuid() == 0) stays a separate skipif beside
the marker, spelled getattr(os, "geteuid", ...) so the decorator still
imports on Windows.
Where the conversion would stack two platforms() marks on one test (the
conftest rejects that at collection) the narrower mark wins:
- test_update_wedged_gateway: the class is already platforms("linux");
its per-test "needs UNIX sockets" marks were redundant and are gone.
- test_process_registry.TestSystemdCgroupIsolation: the class-level
skip-on-Windows moves onto the 11 methods that had no host mark; the
11 platforms("linux") methods keep theirs.
- test_file_ops_single_roundtrip: the two fifo tests drop their
platforms("linux") in favour of the module's "posix" (mkfifo exists on
macOS; both tests already skip when it does not).
- test_linux_desktop_entry / test_gateway_job_teardown_live: duplicate
or wider marks removed.
180 lines
6.0 KiB
Python
180 lines
6.0 KiB
Python
"""macOS CuaDriver.app path and signing identity contracts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
from tools.computer_use import cua_backend
|
|
from tools.computer_use import cua_backend_daemon
|
|
|
|
|
|
def _codesign_proc(
|
|
*,
|
|
team_id: str,
|
|
identifier: str = "com.trycua.driver",
|
|
returncode: int = 0,
|
|
) -> subprocess.CompletedProcess[str]:
|
|
return subprocess.CompletedProcess(
|
|
["codesign"],
|
|
returncode,
|
|
stdout="",
|
|
stderr=(
|
|
f"Identifier={identifier}\n"
|
|
f"TeamIdentifier={team_id}\n"
|
|
),
|
|
)
|
|
|
|
|
|
def _patch_codesign(monkeypatch, proc):
|
|
monkeypatch.setattr(cua_backend_daemon.shutil, "which", lambda name: "/usr/bin/codesign")
|
|
monkeypatch.setattr(cua_backend.subprocess, "run", lambda *args, **kwargs: proc)
|
|
|
|
|
|
@pytest.mark.platforms("posix") # macOS bundle paths use POSIX separators
|
|
def test_resolve_app_path_follows_real_symlink_and_is_idempotent(tmp_path):
|
|
app = tmp_path / "CuaDriver.app"
|
|
executable = app / "Contents" / "MacOS" / "cua-driver"
|
|
executable.parent.mkdir(parents=True)
|
|
executable.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8")
|
|
executable.chmod(0o755)
|
|
shim = tmp_path / "cua-driver"
|
|
try:
|
|
shim.symlink_to(executable)
|
|
except (OSError, NotImplementedError):
|
|
pytest.skip("symlinks are unavailable on this host")
|
|
|
|
assert cua_backend_daemon._resolve_cua_driver_app_path(str(shim)) == str(app)
|
|
assert cua_backend_daemon._resolve_cua_driver_app_path(str(executable)) == str(app)
|
|
|
|
|
|
def test_resolve_app_path_follows_standard_driver_symlink(monkeypatch):
|
|
symlink = "/Users/test/.local/bin/cua-driver"
|
|
executable = "/Applications/CuaDriver.app/Contents/MacOS/cua-driver"
|
|
|
|
monkeypatch.setattr(cua_backend.os.path, "realpath", lambda path: executable)
|
|
monkeypatch.setattr(cua_backend.os.path, "isfile", lambda path: True)
|
|
monkeypatch.setattr(cua_backend.os, "access", lambda path, mode: True)
|
|
|
|
assert cua_backend_daemon._resolve_cua_driver_app_path(symlink) == "/Applications/CuaDriver.app"
|
|
|
|
|
|
def test_resolve_app_path_does_not_fall_back_to_an_unrelated_bundle(monkeypatch):
|
|
monkeypatch.setattr(
|
|
cua_backend.os.path,
|
|
"realpath",
|
|
lambda path: "/usr/local/bin/cua-driver",
|
|
)
|
|
|
|
assert cua_backend_daemon._resolve_cua_driver_app_path("cua-driver") is None
|
|
|
|
|
|
@pytest.mark.parametrize("team_id", ["4YEC26S9KF", "YCK386LBJ7"])
|
|
def test_driver_signature_accepts_official_team_ids(monkeypatch, team_id):
|
|
_patch_codesign(monkeypatch, _codesign_proc(team_id=team_id))
|
|
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_driver_signature_still_rejects_unrecognised_team(monkeypatch):
|
|
_patch_codesign(monkeypatch, _codesign_proc(team_id="EVIL000000"))
|
|
|
|
with pytest.raises(RuntimeError, match="signed by team"):
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_driver_signature_still_requires_exact_bundle_identifier(monkeypatch):
|
|
_patch_codesign(
|
|
monkeypatch,
|
|
_codesign_proc(
|
|
team_id="YCK386LBJ7",
|
|
identifier="com.trycua.driver.evil",
|
|
),
|
|
)
|
|
|
|
with pytest.raises(RuntimeError, match="has identifier"):
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_driver_signature_rejects_unsigned_by_default(monkeypatch):
|
|
_patch_codesign(monkeypatch, _codesign_proc(team_id="not set"))
|
|
monkeypatch.setattr(cua_backend, "_computer_use_cfg", lambda: {})
|
|
|
|
with pytest.raises(RuntimeError, match="signed by team"):
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_driver_signature_allows_unsigned_only_with_opt_in(monkeypatch):
|
|
_patch_codesign(monkeypatch, _codesign_proc(team_id="not set"))
|
|
monkeypatch.setattr(
|
|
cua_backend,
|
|
"_computer_use_cfg",
|
|
lambda: {"allow_unsigned_driver": True},
|
|
)
|
|
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_unsigned_opt_in_still_requires_exact_bundle_identifier(monkeypatch):
|
|
_patch_codesign(
|
|
monkeypatch,
|
|
_codesign_proc(
|
|
team_id="not set",
|
|
identifier="com.trycua.driver.evil",
|
|
),
|
|
)
|
|
monkeypatch.setattr(
|
|
cua_backend,
|
|
"_computer_use_cfg",
|
|
lambda: {"allow_unsigned_driver": True},
|
|
)
|
|
|
|
with pytest.raises(RuntimeError, match="has identifier"):
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_driver_signature_requires_codesign(monkeypatch):
|
|
monkeypatch.setattr(cua_backend_daemon.shutil, "which", lambda name: None)
|
|
|
|
with pytest.raises(RuntimeError, match="codesign is required"):
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_driver_signature_rejects_codesign_failure(monkeypatch):
|
|
_patch_codesign(
|
|
monkeypatch,
|
|
_codesign_proc(team_id="", returncode=1),
|
|
)
|
|
|
|
with pytest.raises(RuntimeError, match="not code-signed"):
|
|
cua_backend_daemon._validate_cua_driver_app_signature("/Applications/CuaDriver.app")
|
|
|
|
|
|
def test_embedded_spawn_resolves_shim_and_accepts_current_team(monkeypatch):
|
|
executable = "/Applications/CuaDriver.app/Contents/MacOS/cua-driver"
|
|
monkeypatch.setattr(cua_backend.os.path, "realpath", lambda path: executable)
|
|
monkeypatch.setattr(cua_backend.os.path, "isfile", lambda path: True)
|
|
monkeypatch.setattr(cua_backend.os, "access", lambda path, mode: True)
|
|
_patch_codesign(monkeypatch, _codesign_proc(team_id="YCK386LBJ7"))
|
|
|
|
command = cua_backend_daemon._embedded_daemon_spawn_command(
|
|
"/Users/test/.local/bin/cua-driver",
|
|
["serve", "--embedded", "--socket", "/tmp/private.sock"],
|
|
platform="darwin",
|
|
)
|
|
|
|
assert command == [
|
|
"/usr/bin/open",
|
|
"-n",
|
|
"-g",
|
|
"-a",
|
|
"/Applications/CuaDriver.app",
|
|
"--args",
|
|
"serve",
|
|
"--embedded",
|
|
"--socket",
|
|
"/tmp/private.sock",
|
|
]
|