fix: reject incomplete source installer arguments before install work

This commit is contained in:
ethernet
2026-09-24 09:07:45 -04:00
parent b207701287
commit ff14aaecc0
3 changed files with 40 additions and 10 deletions

View File

@@ -273,11 +273,12 @@ def detect_install_method(project_root: Optional[Path] = None) -> str:
``hermes update`` refuse to run. A legacy ``docker`` value is therefore ignored unless we are
really inside a container, and being in a container alone never implies 'docker'.
The supported installs self-identify via the code-scoped stamp: - the curl installer
(scripts/install.sh, the README/website install command) git-clones the repo and stamps ``git`` next to
the code; - the published ``nousresearch/hermes-agent`` image bakes a ``docker`` stamp into
``/opt/hermes`` at build time. An unsupported manual install dropped into a container (no stamp) falls
through to the ``.git`` checks and behaves like any off-path install. See issue #34397.
Source installers clone a git checkout and publish ``install-stamp.json``;
the ``.git`` fallback identifies it as a source install. Older installations
may carry ``.install_method``, which remains authoritative for compatibility.
The published image bakes a ``docker`` marker into ``/opt/hermes``. A manual
clone in a container still resolves via ``.git``, not container presence alone.
See issue #34397.
"""
# The stamp is a property of the running code tree (parent of hermes_cli/), NOT of $HERMES_HOME,
# so it survives two installs sharing a home.

View File

@@ -31,12 +31,21 @@ INCLUDE_DESKTOP=false
while [ $# -gt 0 ]; do
case "$1" in
--branch|-Branch) BRANCH="${2:?--branch needs a value}"; shift 2 ;;
--commit|-Commit) INSTALL_COMMIT="$2"; shift 2 ;;
--dir) INSTALL_DIR="$2"; shift 2 ;;
--hermes-home|-HermesHome) HERMES_HOME="$2"; shift 2 ;;
--branch|-Branch|--commit|-Commit|--dir|--hermes-home|-HermesHome|--stage|-Stage)
option="$1"
if [ $# -lt 2 ] || [ -z "$2" ] || [[ "$2" == -* ]]; then
printf '%s needs a value\n' "$option" >&2
exit 2
fi
case "$option" in
--branch|-Branch) BRANCH="$2" ;;
--commit|-Commit) INSTALL_COMMIT="$2" ;;
--dir) INSTALL_DIR="$2" ;;
--hermes-home|-HermesHome) HERMES_HOME="$2" ;;
--stage|-Stage) STAGE="$2" ;;
esac
shift 2 ;;
--manifest|-Manifest) WANT_MANIFEST=true; shift ;;
--stage|-Stage) STAGE="$2"; shift 2 ;;
--json|-Json) JSON=true; shift ;;
--non-interactive|-NonInteractive) NON_INTERACTIVE=true; shift ;;
--skip-setup) NON_INTERACTIVE=true; shift ;;

View File

@@ -21,6 +21,26 @@ INSTALL_SH = ROOT / "scripts/install.sh"
pytestmark = pytest.mark.platforms("posix")
@pytest.mark.parametrize("option", ["--branch", "--commit", "--dir", "--hermes-home", "--stage"])
@pytest.mark.parametrize("suffix", [[], ["--manifest"], [""]])
def test_missing_value_fails_before_any_install_work(option: str, suffix: list[str]) -> None:
result = subprocess.run(["bash", str(INSTALL_SH), option, *suffix],
capture_output=True, text=True, timeout=10)
assert result.returncode == 2
assert result.stderr.strip() == f"{option} needs a value"
assert not result.stdout
@pytest.mark.parametrize("flag", ["--skip-browser", "--no-playwright"])
def test_removed_browser_skip_never_becomes_noninteractive(flag: str) -> None:
result = subprocess.run(["bash", str(INSTALL_SH), flag, "--manifest"],
capture_output=True, text=True, timeout=10)
assert result.returncode == 1
assert "no longer skips the browser install" in result.stderr
assert "--non-interactive" in result.stderr
assert not result.stdout
def _environment(tmp_path: Path) -> tuple[Path, Path, dict[str, str]]:
core = tmp_path / "checkout"
(core / "pm").mkdir(parents=True)