diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 77eedc6d1c..b39a3255d4 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -139,11 +139,15 @@ done # # These are test-infrastructure knobs, not credentials — same class as the # HERMES_RUN_SLOW_PET_TESTS / HERMES_E2E_BROWSER opt-ins already forwarded. +# SSL_CERT_FILE/DIR are trust-store locations: the pinned interpreter's +# OpenSSL has no compiled-in bundle path on NixOS, so network tests (PM +# downloads, channel reads) need the host's pointer to verify TLS. # Keep this an explicit allowlist (no HERMES_TEST_* glob) so the "no # credential can leak" property stays auditable at a glance. TEST_ENV=() for _test_var in HERMES_TEST_IMAGE HERMES_TEST_WORKERS HERMES_TEST_PATHS \ - HERMES_TEST_FILE_TIMEOUT HERMES_TEST_FILE_RETRIES HERMES_TEST_SLICE; do + HERMES_TEST_FILE_TIMEOUT HERMES_TEST_FILE_RETRIES HERMES_TEST_SLICE \ + SSL_CERT_FILE SSL_CERT_DIR; do if [ -n "${!_test_var:-}" ]; then TEST_ENV+=("$_test_var=${!_test_var}") fi diff --git a/tests/agent/test_astra_baseline_runtime.py b/tests/agent/test_astra_baseline_runtime.py index b1fad0e133..41899220fa 100644 --- a/tests/agent/test_astra_baseline_runtime.py +++ b/tests/agent/test_astra_baseline_runtime.py @@ -59,7 +59,7 @@ def test_astra_900k_opt_in_preserves_live_limits_and_wire_contract(monkeypatch, monkeypatch.setenv("HERMES_HOME", str(tmp_path)) monkeypatch.setattr(metadata, "_codex_oauth_context_cache", {}) - monkeypatch.setattr(metadata.requests, "get", lambda *args, **kwargs: SimpleNamespace( + monkeypatch.setattr(metadata.model_metadata_http, "get", lambda *args, **kwargs: SimpleNamespace( status_code=200, json=lambda: {"models": [{"slug": "gpt-6-astra", "context_window": advertised}]}, )) diff --git a/tests/agent/test_warning_presentation.py b/tests/agent/test_warning_presentation.py index a2c928023d..664714e59c 100644 --- a/tests/agent/test_warning_presentation.py +++ b/tests/agent/test_warning_presentation.py @@ -144,7 +144,6 @@ def test_missing_key_banner_is_classified_without_hiding_initialization(tmp_path monkeypatch.setattr(agent_init, "_explicit_client_kwargs", lambda *a: {"api_key": "dummy-key", "base_url": agent.base_url}) monkeypatch.setattr(agent_init, "_apply_openai_header_policy", lambda *a: None) - monkeypatch.setattr("agent.ssl_guard.verify_ca_bundle", lambda: None) agent_init._init_openai_client(agent, "dummy-key", agent.base_url, None, 30) output = capsys.readouterr().out assert ("API key appears invalid or missing" in output) is (suppress is not True) diff --git a/tests/hermes_cli/test_codex_models.py b/tests/hermes_cli/test_codex_models.py index 78a057711f..ae78b85294 100644 --- a/tests/hermes_cli/test_codex_models.py +++ b/tests/hermes_cli/test_codex_models.py @@ -303,8 +303,7 @@ def test_catalog_requests_use_ungated_client_version(monkeypatch): monkeypatch.setitem(sys.modules, "httpx", _FakeHttpx) codex_models._fetch_models_from_api(access_token="tok") - monkeypatch.setattr(model_metadata, "requests", _FakeRequests) - monkeypatch.setattr(model_metadata, "_ensure_requests", lambda: None) + monkeypatch.setattr(model_metadata.model_metadata_http, "get", _FakeRequests.get) monkeypatch.setattr(model_metadata, "_codex_oauth_context_cache", {}) model_metadata._fetch_codex_oauth_context_lengths_with_source("tok") diff --git a/tests/hermes_cli/test_profile_rename_checkpoints.py b/tests/hermes_cli/test_profile_rename_checkpoints.py index 957da2b5f6..92e01ebcf3 100644 --- a/tests/hermes_cli/test_profile_rename_checkpoints.py +++ b/tests/hermes_cli/test_profile_rename_checkpoints.py @@ -68,7 +68,7 @@ def test_rename_preserves_profile_local_checkpoint_history(profile_env, tmp_path assert str(new_workdir.resolve()) in project_paths assert str(workdir.resolve()) not in project_paths - plan = manager.safe_restore_plan(str(new_workdir), checkpoint_hash) + plan = manager._safe_restore_plan(str(new_workdir), checkpoint_hash) assert plan["success"] is True assert plan["restore"] == ["note.txt"] assert plan["skipped"] == [] diff --git a/tests/hermes_cli/test_profiles.py b/tests/hermes_cli/test_profiles.py index 85535b2c48..35e5187342 100644 --- a/tests/hermes_cli/test_profiles.py +++ b/tests/hermes_cli/test_profiles.py @@ -1702,11 +1702,12 @@ class TestCloneAllExcludesRuntimeTrees: def test_runtime_trio_is_one_constant_shared_with_backup(self): """backup's exclusion list and the clone-all root gate must be built from the same - constant; two literals drifting apart is how the models/ copy of #111718 crept in.""" + constant; two literals drifting apart is how the models/ copy of #111718 crept in. + backup additionally drops PM's regenerable trees; it never drops less.""" from hermes_cli import backup, profiles from hermes_constants import LOCAL_RUNTIME_ROOT_DIRS assert LOCAL_RUNTIME_ROOT_DIRS == frozenset(self.RUNTIME_TREES) - assert backup._EXCLUDED_ROOT_DIRS is LOCAL_RUNTIME_ROOT_DIRS + assert LOCAL_RUNTIME_ROOT_DIRS <= backup._EXCLUDED_ROOT_DIRS assert LOCAL_RUNTIME_ROOT_DIRS <= profiles._CLONE_ALL_DEFAULT_EXCLUDE_ROOT def test_clone_all_from_default_skips_runtime_trees_but_keeps_the_rest(self, profile_env): diff --git a/tools/checkpoint_manager.py b/tools/checkpoint_manager.py index 2a295dcff6..c36fbffab2 100644 --- a/tools/checkpoint_manager.py +++ b/tools/checkpoint_manager.py @@ -222,6 +222,10 @@ def _store_path(base: Optional[Path] = None) -> Path: return (base or _resolve_checkpoint_base()) / _STORE_DIRNAME +def _store_has_head(store: Path) -> bool: + return (store / "HEAD").exists() + + def _index_path(store: Path, dir_hash: str) -> Path: return store / _INDEXES_DIRNAME / dir_hash @@ -405,6 +409,29 @@ def _run_git( return False, "", str(exc) +def _git_out(args: List[str], store: Path, working_dir: str, rc: Optional[Set[int]] = None) -> str: + """stdout of a successful git call, else ``""``.""" + ok, out, _ = _run_git(args, store, working_dir, allowed_returncodes=rc) + return out if ok else "" + + +def _ref_tip(store: Path, working_dir: str, ref: str) -> Optional[str]: + """Commit sha at ``ref``, or None when the ref does not exist yet.""" + return _git_out(["rev-parse", "--verify", ref + "^{commit}"], store, working_dir, {128}) or None + + +def _list_project_refs(store: Path, working_dir: str) -> List[str]: + out = _git_out(["for-each-ref", "--format=%(refname)", _REFS_PREFIX], store, working_dir, {128}) + return [r for r in out.splitlines() if r.strip()] + + +def _unlink_quiet(path: Path) -> None: + try: + path.unlink(missing_ok=True) + except OSError: + pass + + # --------------------------------------------------------------------------- # Store initialisation + legacy migration # ---------------------------------------------------------------------------