From 5e8fbd4919d79d7474f2b89c655eb3d8ae8d64c2 Mon Sep 17 00:00:00 2001 From: ethernet Date: Mon, 21 Sep 2026 18:41:42 -0400 Subject: [PATCH] install.sh: refuse Termux hosts and point at the APT package check_platform accepted Termux as plain Linux, so `curl | bash` on a phone walked the source-install ladder: a glibc uv, a lock whose CPython is the bundled bionic build with no Android wheels, and on-device sdist builds. The signed APT package is the only supported Termux shape, so detect Termux the way the runtime does (TERMUX_VERSION or the com.termux PREFIX) and stop before any stage with `pkg install hermes-agent` and the setup docs URL. --json surfaces the reason in the stage frame. --- scripts/install.sh | 6 ++++ .../install/test_install_sh_termux_refusal.py | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/scripts/install/test_install_sh_termux_refusal.py diff --git a/scripts/install.sh b/scripts/install.sh index 69721233de..edceb2541c 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -190,6 +190,12 @@ ensure_uv() { } check_platform() { + # Termux is Linux by uname, but this installer builds a glibc source + # install the phone cannot run (no Android wheels in the lock). The + # signed APT package is the only supported shape there. + if [ -n "${TERMUX_VERSION:-}" ] || case "${PREFIX:-}" in *com.termux/files/usr*) true ;; *) false ;; esac; then + fail "Termux is installed from its APT repository, not install.sh: pkg install hermes-agent (setup: https://hermes-agent.nousresearch.com/docs/getting-started/termux)" + fi case "$(uname -s 2>/dev/null)" in Linux*) : ;; Darwin*) : ;; diff --git a/tests/scripts/install/test_install_sh_termux_refusal.py b/tests/scripts/install/test_install_sh_termux_refusal.py new file mode 100644 index 0000000000..d42c4646b2 --- /dev/null +++ b/tests/scripts/install/test_install_sh_termux_refusal.py @@ -0,0 +1,29 @@ +"""install.sh sends Termux hosts to the APT package instead of building a source install.""" +import os +from pathlib import Path +import subprocess + +import pytest + +INSTALL_SH = Path(__file__).resolve().parent.parent.parent.parent / "scripts" / "install.sh" + + +@pytest.mark.parametrize("marker", [{"TERMUX_VERSION": "0.118.0"}, {"PREFIX": "/data/data/com.termux/files/usr"}]) +def test_termux_host_is_refused_before_any_stage_with_apt_hint(tmp_path, marker): + env = {k: v for k, v in os.environ.items() if k not in ("TERMUX_VERSION", "PREFIX")} + env.update(marker, HOME=tmp_path.as_posix(), HERMES_HOME=(tmp_path / "home").as_posix(), + HERMES_INSTALL_DIR=(tmp_path / "install").as_posix()) + result = subprocess.run(["bash", INSTALL_SH.as_posix(), "--stage", "prerequisites"], + env=env, capture_output=True, text=True, timeout=30) + assert result.returncode != 0 + assert "pkg install hermes-agent" in result.stderr + assert not (tmp_path / "install").exists() + + +def test_plain_linux_host_passes_platform_check(tmp_path): + env = {k: v for k, v in os.environ.items() if k not in ("TERMUX_VERSION", "PREFIX")} + env.update(HOME=tmp_path.as_posix(), HERMES_HOME=(tmp_path / "home").as_posix(), + HERMES_INSTALL_DIR=(tmp_path / "install").as_posix()) + result = subprocess.run(["bash", INSTALL_SH.as_posix(), "--stage", "prerequisites"], + env=env, capture_output=True, text=True, timeout=30) + assert result.returncode == 0, result.stderr