Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions hermes_cli/managed_uv.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
_VENV_NAME = "venv"
_ALT_VENV_NAME = ".venv"
_REPAIR_LOCK_NAME = "runtime-repair.lock"
_MACOS_MANAGED_PYTHON_IDENTIFIER = "com.nousresearch.hermes.managed-python"

# ---------------------------------------------------------------------------
# Public helpers
Expand Down Expand Up @@ -116,6 +117,79 @@ def managed_python_env(
return env


def _macos_sign_managed_python(python: Path) -> bool:
"""Give a newly downloaded managed Python a stable macOS code identity.

python-build-standalone binaries are ad-hoc signed, which leaves macOS
TCC with a cdhash-only identity that changes whenever Hermes provisions a
new runtime generation. An identifier-pinned designated requirement
gives those generations a stable identity even when no Developer ID
certificate is available locally.

Signing is deliberately best effort. Runtime repair exists to remove a
security vulnerability, so an unavailable or incompatible ``codesign``
must not prevent the fixed interpreter from being installed.
"""
if platform.system() != "Darwin":
return False

codesign = shutil.which("codesign")
if not codesign:
logger.info(
"macOS codesign is unavailable; using the downloaded Python signature"
)
return False

requirement = (
"=designated => identifier "
f'"{_MACOS_MANAGED_PYTHON_IDENTIFIER}"'
)
try:
signed = subprocess.run(
[
codesign,
"--force",
"--deep",
"--sign",
"-",
"--timestamp=none",
"--identifier",
_MACOS_MANAGED_PYTHON_IDENTIFIER,
"--requirements",
requirement,
str(python),
],
check=False,
capture_output=True,
text=True,
)
if signed.returncode != 0:
logger.warning(
"could not stably sign managed Python %s: %s",
python,
(signed.stderr or signed.stdout or "codesign failed").strip(),
)
return False

verified = subprocess.run(
[codesign, "--verify", "--deep", "--strict", str(python)],
check=False,
capture_output=True,
text=True,
)
if verified.returncode != 0:
logger.warning(
"macOS signature verification failed for managed Python %s: %s",
python,
(verified.stderr or verified.stdout or "verification failed").strip(),
)
return False
return True
except Exception as exc:
logger.warning("could not sign managed Python %s: %s", python, exc)
return False


@dataclass(frozen=True)
class RuntimeRepairResult:
"""Outcome of a managed-runtime repair attempt."""
Expand Down Expand Up @@ -588,6 +662,12 @@ def _attempt_install_generation(
_remove_tree(generation, boundary=python_root)
return None

# Do this before the candidate is probed or promoted. On macOS, the
# stable identifier prevents each immutable generation from looking like
# a new TCC principal. Failure is non-fatal: the SQLite repair must still
# proceed when codesign is unavailable or rejects a particular artifact.
_macos_sign_managed_python(python)

candidate = probe_sqlite_runtime(python)
if candidate is None:
logger.warning("could not probe candidate Python runtime: %s", python)
Expand Down
69 changes: 68 additions & 1 deletion tests/hermes_cli/test_managed_uv.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,74 @@ def test_posix(self, tmp_path):
assert managed_uv_path() == tmp_path / "bin" / "uv"


class TestMacOSManagedPythonSigning:
def test_signs_with_stable_identifier_and_verifies(self, tmp_path, monkeypatch):
import hermes_cli.managed_uv as managed_uv

python = tmp_path / "generation" / "bin" / "python3.11"
python.parent.mkdir(parents=True)
python.touch()
calls = []

def fake_run(cmd, **kwargs):
calls.append((cmd, kwargs))
return SimpleNamespace(returncode=0, stdout="", stderr="")

monkeypatch.setattr(managed_uv.platform, "system", lambda: "Darwin")
monkeypatch.setattr(managed_uv.shutil, "which", lambda name: "/usr/bin/codesign")
monkeypatch.setattr(managed_uv.subprocess, "run", fake_run)

assert managed_uv._macos_sign_managed_python(python) is True
assert calls[0][0] == [
"/usr/bin/codesign",
"--force",
"--deep",
"--sign",
"-",
"--timestamp=none",
"--identifier",
"com.nousresearch.hermes.managed-python",
"--requirements",
'=designated => identifier "com.nousresearch.hermes.managed-python"',
str(python),
]
assert calls[1][0] == [
"/usr/bin/codesign",
"--verify",
"--deep",
"--strict",
str(python),
]

def test_is_non_blocking_when_signing_fails(self, tmp_path, monkeypatch):
import hermes_cli.managed_uv as managed_uv

python = tmp_path / "python3.11"
monkeypatch.setattr(managed_uv.platform, "system", lambda: "Darwin")
monkeypatch.setattr(managed_uv.shutil, "which", lambda name: "/usr/bin/codesign")
monkeypatch.setattr(
managed_uv.subprocess,
"run",
lambda *args, **kwargs: SimpleNamespace(
returncode=1, stdout="", stderr="not signable"
),
)

assert managed_uv._macos_sign_managed_python(python) is False

def test_skips_non_macos(self, tmp_path, monkeypatch):
import hermes_cli.managed_uv as managed_uv

monkeypatch.setattr(managed_uv.platform, "system", lambda: "Linux")
monkeypatch.setattr(
managed_uv.subprocess,
"run",
lambda *args, **kwargs: pytest.fail("codesign must not run on Linux"),
)

assert managed_uv._macos_sign_managed_python(tmp_path / "python") is False


# ---------------------------------------------------------------------------
# resolve_uv
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -1099,4 +1167,3 @@ def _no_reload(module): # pragma: no cover - must not run
assert _venv_python(Path("/opt/hermes/venv")) == Path(
"/opt/hermes/venv/bin/python"
)