fix(vector): close local pgvector final review
This commit is contained in:
@@ -245,8 +245,9 @@ def test_pgvector_writer_health_requires_sequence_usage(vector_configs):
|
||||
assert health.write_detail == (
|
||||
"vector schema incomplete: missing sequence privileges evidence, memory, schema_records"
|
||||
)
|
||||
with pytest.raises(InsufficientPrivilege):
|
||||
with pytest.raises(VectorWriteUnavailable) as error:
|
||||
store.upsert("memory", [_record("needs-sequence", [1.0, 0.0])])
|
||||
assert isinstance(error.value.__cause__, InsufficientPrivilege)
|
||||
|
||||
admin_engine = create_engine(
|
||||
f"postgresql+psycopg2://{admin_config.user}:{admin_config.password}"
|
||||
@@ -262,6 +263,53 @@ def test_pgvector_writer_health_requires_sequence_usage(vector_configs):
|
||||
assert store.upsert("memory", [_record("has-sequence", [1.0, 0.0])]) == 1
|
||||
|
||||
|
||||
def test_pgvector_health_requires_schema_usage_for_reader_and_writer(vector_configs):
|
||||
from tht.adapters.vector.pgvector import PgVectorStore
|
||||
|
||||
admin_config, reader_config, writer_config, _ = vector_configs
|
||||
admin_engine = create_engine(
|
||||
f"postgresql+psycopg2://{admin_config.user}:{admin_config.password}"
|
||||
f"@{admin_config.host}:{admin_config.port}/{admin_config.database}"
|
||||
)
|
||||
store = PgVectorStore(reader_config, writer_config, expected_dimension=2)
|
||||
with admin_engine.begin() as connection:
|
||||
connection.exec_driver_sql(
|
||||
f"REVOKE USAGE ON SCHEMA vectors FROM {reader_config.user}, {writer_config.user}"
|
||||
)
|
||||
health = store.health()
|
||||
assert health.read_reachable is False and health.write_reachable is False
|
||||
assert "missing schema usage" in health.read_detail
|
||||
assert "missing schema usage" in health.write_detail
|
||||
with pytest.raises(VectorReadUnavailable, match="Vector read operation unavailable"):
|
||||
store.search(["memory"], [1.0, 0.0], limit=1)
|
||||
with pytest.raises(VectorWriteUnavailable, match="Vector write operation unavailable"):
|
||||
store.upsert("memory", [_record("blocked", [1.0, 0.0])])
|
||||
with admin_engine.begin() as connection:
|
||||
connection.exec_driver_sql(
|
||||
f"GRANT USAGE ON SCHEMA vectors TO {reader_config.user}, {writer_config.user}"
|
||||
)
|
||||
admin_engine.dispose()
|
||||
assert store.health().ok is True
|
||||
|
||||
|
||||
def test_pgvector_maps_unavailable_connections_without_leaking_password(vector_configs):
|
||||
from tht.adapters.vector.pgvector import PgVectorStore
|
||||
|
||||
_, reader_config, writer_config, _ = vector_configs
|
||||
password = "never-leak-this"
|
||||
reader = reader_config.model_copy(update={"port": 1, "password": password})
|
||||
writer = writer_config.model_copy(update={"port": 1, "password": password})
|
||||
with pytest.raises(VectorReadUnavailable) as read_error:
|
||||
PgVectorStore(reader, None).search(["memory"], [1.0, 0.0], limit=1)
|
||||
with pytest.raises(VectorWriteUnavailable) as hash_error:
|
||||
PgVectorStore(None, writer).existing_hashes("memory", ["memory"])
|
||||
with pytest.raises(VectorWriteUnavailable) as write_error:
|
||||
PgVectorStore(None, writer).upsert("memory", [_record("x", [1.0, 0.0])])
|
||||
assert password not in str(read_error.value)
|
||||
assert password not in str(hash_error.value)
|
||||
assert password not in str(write_error.value)
|
||||
|
||||
|
||||
def test_pgvector_health_reports_dimension_and_each_connection(vector_configs):
|
||||
from tht.adapters.vector.pgvector import PgVectorStore
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from tht.config import (
|
||||
ConfigError,
|
||||
PgvectorDirectConfig,
|
||||
PostgresDwhConfig,
|
||||
ThothRestDwhConfig,
|
||||
@@ -7,6 +10,44 @@ from tht.config import (
|
||||
)
|
||||
|
||||
|
||||
def test_direct_vector_passwords_load_from_file_references(monkeypatch, tmp_path):
|
||||
reader = tmp_path / "reader"
|
||||
writer = tmp_path / "writer"
|
||||
reader.write_text("reader-secret")
|
||||
writer.write_text("writer-secret")
|
||||
monkeypatch.setenv("READER_FILE", str(reader))
|
||||
monkeypatch.setenv("WRITER_FILE", str(writer))
|
||||
workspace = tmp_path / "workspace.yaml"
|
||||
workspace.write_text("""
|
||||
dwh:
|
||||
type: postgres_direct
|
||||
connection: {database: d, schema: public, user: u, password: p}
|
||||
vectors:
|
||||
type: pgvector_direct
|
||||
reader: {database: d, schema: vectors, user: r, password_file: '${READER_FILE}'}
|
||||
writer: {database: d, schema: vectors, user: w, password_file: '${WRITER_FILE}'}
|
||||
""")
|
||||
config = load_config(workspace)
|
||||
assert config.vectors.reader.password == "reader-secret"
|
||||
assert config.vectors.writer.password == "writer-secret"
|
||||
|
||||
|
||||
def test_direct_vector_secret_file_rejects_whitespace(tmp_path):
|
||||
secret = tmp_path / "reader"
|
||||
secret.write_text("bad secret")
|
||||
workspace = tmp_path / "workspace.yaml"
|
||||
workspace.write_text(f"""
|
||||
dwh:
|
||||
type: postgres_direct
|
||||
connection: {{database: d, schema: public, user: u, password: p}}
|
||||
vectors:
|
||||
type: pgvector_direct
|
||||
reader: {{database: d, schema: vectors, user: r, password_file: {secret}}}
|
||||
""")
|
||||
with pytest.raises(ConfigError, match="secret file"):
|
||||
load_config(workspace)
|
||||
|
||||
|
||||
def test_loads_discriminated_dwh_and_vector_resources(tmp_path):
|
||||
workspace = tmp_path / "workspace.yaml"
|
||||
workspace.write_text(
|
||||
|
||||
Reference in New Issue
Block a user