"""L1: dual vector API key (spec D11, ยง5.4). The reader (search_similar) and the writer (upsert_vector_records) use SEPARATE API keys against the same pgvector REST endpoint, with distinct roles (vector_reader / vector_writer). This test pins the dual-key construction and the workstation write-guard. """ from tht.cli._guards import has_vector_write_rest, require_vector_write_allowed from tht.config import Config, DatabaseConfig, RestConfig from tht.vectorstore.rest_client import VectorRestClient def _minimal_config(**kw) -> Config: base = dict( database=DatabaseConfig(database="db", schema="dw", user="u", password="p"), ) base.update(kw) return Config(**base) def test_reader_and_writer_use_separate_keys(): reader = VectorRestClient(RestConfig(base_url="https://v/", api_key="K-READ")) writer = VectorRestClient(RestConfig(base_url="https://v/", api_key="K-WRITE")) assert reader.api_key == "K-READ" assert writer.api_key == "K-WRITE" def test_has_vector_write_rest_false_for_empty_key(): cfg = _minimal_config(vector_write_rest=RestConfig(base_url="x", api_key=" ")) assert has_vector_write_rest(cfg) is False def test_has_vector_write_rest_false_when_absent(): cfg = _minimal_config() assert has_vector_write_rest(cfg) is False def test_has_vector_write_rest_true_when_key_present(): cfg = _minimal_config(vector_write_rest=RestConfig(base_url="x", api_key="K-WRITE")) assert has_vector_write_rest(cfg) is True def test_require_vector_write_allowed_blocks_workstation_without_key(): import typer cfg = _minimal_config(profile="workstation") # no vector_write_rest try: require_vector_write_allowed(cfg, "memory save-one") assert False, "should have exited with code 4" except typer.Exit as e: assert e.exit_code == 4 def test_require_vector_write_allowed_allows_workstation_with_key(): cfg = _minimal_config( profile="workstation", vector_write_rest=RestConfig(base_url="x", api_key="K-WRITE"), ) require_vector_write_allowed(cfg, "memory save-one") # no exit -> ok def test_require_vector_write_allowed_allows_server_without_key(): # server profile can use direct vectordb; the REST write guard does not apply. cfg = _minimal_config(profile="server") require_vector_write_allowed(cfg, "memory save-one") # no exit -> ok