"""Unit tests for ``neuronetz_gateway.proxy.allowlist``. Two concerns (SPEC §4.3 step 7-8, §4.6, §6.1-6.2): 1. **Hard-blocked endpoints** — mutating Ollama endpoints and ``/api/ps`` are always blocked, not configurable (``is_hard_blocked``). 2. **Effective model set** (``resolve_effective_models`` / ``is_model_allowed``): * ``allow_all`` ⇒ all discovered * default-deny ⇒ ``allowed_models ∩ discovered`` * stale/typo'd allowlist entries never resolve (not in discovered) * empty discovered ⇒ deny, even under ``allow_all`` (fail-closed) The resolver merges the *already-resolved* ``allow_all``/``allowed_models`` inputs (key-vs-tenant precedence per SPEC §13.7 is applied by the caller before this point; that precedence is exercised in the integration model-discovery tests). """ from __future__ import annotations import pytest from neuronetz_gateway.proxy import allowlist # --- hard-blocked endpoint allowlist --------------------------------------- @pytest.mark.parametrize( "path", ["/api/pull", "/api/push", "/api/create", "/api/copy", "/api/delete", "/api/ps"], ) def test_mutating_and_ps_endpoints_hard_blocked(path: str) -> None: assert allowlist.is_hard_blocked(path) is True @pytest.mark.parametrize("path", ["/api/blobs", "/api/blobs/sha256:abc", "/api/blobs/x/y"]) def test_blob_prefix_hard_blocked(path: str) -> None: assert allowlist.is_hard_blocked(path) is True @pytest.mark.parametrize( "path", ["/api/chat", "/api/generate", "/api/embed", "/api/tags", "/api/show", "/api/version"] ) def test_allowlisted_endpoints_not_hard_blocked(path: str) -> None: assert allowlist.is_hard_blocked(path) is False # --- effective-set resolution (SPEC §4.3 step 7 / §4.6) -------------------- DISCOVERED = frozenset({"llama3.1:8b", "mistral:7b", "nomic-embed-text"}) def test_allow_all_returns_all_discovered() -> None: eff = allowlist.resolve_effective_models( allow_all=True, allowed_models=(), discovered=DISCOVERED ) assert eff == DISCOVERED def test_default_deny_intersects_discovered() -> None: # "qwen" is allowed but not installed => must not resolve (stale entry). eff = allowlist.resolve_effective_models( allow_all=False, allowed_models=("llama3.1:8b", "qwen:0.5b"), discovered=DISCOVERED, ) assert eff == frozenset({"llama3.1:8b"}) def test_default_deny_empty_allowlist_denies_all() -> None: eff = allowlist.resolve_effective_models( allow_all=False, allowed_models=(), discovered=DISCOVERED ) assert eff == frozenset() def test_empty_discovered_denies_everything_even_allow_all() -> None: # Fail-closed: empty discovered set => no model resolves, even allow_all. eff = allowlist.resolve_effective_models( allow_all=True, allowed_models=("llama3.1:8b",), discovered=frozenset() ) assert eff == frozenset() def test_is_model_allowed_membership() -> None: assert ( allowlist.is_model_allowed( "llama3.1:8b", allow_all=False, allowed_models=("llama3.1:8b",), discovered=DISCOVERED ) is True ) # Installed but not permitted. assert ( allowlist.is_model_allowed( "mistral:7b", allow_all=False, allowed_models=("llama3.1:8b",), discovered=DISCOVERED ) is False ) # Permitted but not installed (typo'd / stale) — indistinguishable from # not-allowed to the caller (SPEC §13.6 no existence disclosure). assert ( allowlist.is_model_allowed( "ghost:1b", allow_all=False, allowed_models=("ghost:1b",), discovered=DISCOVERED ) is False ) def test_is_model_allowed_fail_closed_empty_discovered() -> None: assert ( allowlist.is_model_allowed( "llama3.1:8b", allow_all=True, allowed_models=(), discovered=frozenset() ) is False )