#!/usr/bin/env python3 """Pre-commit hook: enforce that journal_quality.db is opened read-only. The compiled journal-quality DB has exactly one writer — `build_db()` in `src/local_deep_research/journal_quality/db.py`. Every other consumer must open the file with SQLite URI flag `mode=ro` (and ideally also `immutable=1`). This hook scans staged Python files for opens of `journal_quality.db` or the legacy `journal_reference.db` and fails the commit if any of them is missing the `mode=ro` flag, OR if the open lives outside the single allowed writer module. """ from __future__ import annotations import re import sys from pathlib import Path ALLOWED_WRITER = "src/local_deep_research/journal_quality/db.py" DB_NAME_PATTERN = re.compile(r"journal_(quality|reference)\.db") MODE_RO_PATTERN = re.compile(r"mode\s*=\s*ro", re.IGNORECASE) def check_file(path: Path) -> list[str]: """Return list of human-readable error messages for `path`.""" errors: list[str] = [] if str(path).endswith(ALLOWED_WRITER): return errors # the writer module is allowed to open writable if not path.suffix == ".py": return errors try: content = path.read_text(encoding="utf-8", errors="replace") except OSError: return errors for lineno, line in enumerate(content.splitlines(), start=1): if not DB_NAME_PATTERN.search(line): continue # Skip comments and string-literal references that aren't opens stripped = line.lstrip() if stripped.startswith("#"): continue # Skip lines that are just naming the file (e.g. f-strings used # for log messages, dict keys, file existence checks) is_open_call = any( tok in line for tok in ( "sqlite3.connect", "create_engine", ".connect(", "open(", ) ) if not is_open_call: continue if not MODE_RO_PATTERN.search(line): errors.append( f"{path}:{lineno}: opens journal_quality.db without " f"mode=ro — only `journal_quality/db.py::build_db` may " f"open the file writable." ) return errors def main(argv: list[str]) -> int: files = [Path(p) for p in argv[1:]] if not files: return 0 all_errors: list[str] = [] for f in files: all_errors.extend(check_file(f)) if all_errors: print( "ERROR: journal_quality.db read-only invariant violated:", file=sys.stderr, ) for err in all_errors: print(f" {err}", file=sys.stderr) print( "\nThe compiled journal-quality DB is read-only at runtime." " The only writer is `build_db()` in " f"{ALLOWED_WRITER}. Open the file with " 'sqlite3.connect(f"file:{path}?mode=ro&immutable=1", uri=True)' " everywhere else.", file=sys.stderr, ) return 1 return 0 if __name__ == "__main__": sys.exit(main(sys.argv))