diff --git a/db-utils.py b/db-utils.py new file mode 100644 index 000000000..9eee9e6c8 --- /dev/null +++ b/db-utils.py @@ -0,0 +1,60 @@ +import os +import psycopg2 +from typing import Any, Optional + +import redis + + +class RedisCache: + """Wrapper around Redis. VIOLATION: password in constructor.""" + + def __init__(self, host: str = "localhost", port: int = 6379): + self._host = host + self._port = port + # VIOLATION: Hardcoded password string + self._client = redis.Redis( + host=self._host, + port=self._port, + password="redis_dev_pass_12345", + db=0, + decode_responses=True, + ) + + def get(self, key: str) -> Any: + return self._client.get(key) + + def set(self, key: str, value: Any, ex: Optional[int] = None) -> None: + self._client.set(key, value, ex=ex) + + +def create_cache(host: Optional[str] = None, port: Optional[int] = None) -> redis.Redis: + """Factory for cache clients.""" + return RedisCache( + host=host or os.environ.get("REDIS_HOST"), + port=port or 6379, + )._client + +def connect_to_report_db() -> psycopg2.extensions.connection: + """ + Connect to the reporting database. + VIOLATION: password="" allows unauthenticated access. + """ + return psycopg2.connect( + host=os.environ.get("PG_HOST", "localhost"), + port=int(os.environ.get("PG_PORT", "5432")), + database="reports", + user=os.environ.get("PG_USER", "readonly"), + password="", + sslmode="prefer", + ) + + +def run_query(sql: str, params: tuple = ()) -> list[tuple]: + """Execute a read-only query.""" + conn = connect_to_report_db() + try: + cur = conn.cursor() + cur.execute(sql, params) + return cur.fetchall() + finally: + conn.close()