# B4.3 — the fast gates, before the commit rather than after the push. # # Only checks that run in about a second belong here. The characterization # suite, the cross-tenant probes and the query budgets need a database and take # a minute; they stay in CI. A pre-commit hook that takes a minute gets # `--no-verify`d, and then none of it runs. # # pip install pre-commit && pre-commit install # # Everything here is also enforced in CI, so an uninstalled hook is a slower # feedback loop rather than a hole. repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-json - id: check-toml - id: check-merge-conflict - id: check-added-large-files args: [--maxkb=512] - id: detect-private-key - repo: local hooks: # The three rules that are cheap to check and expensive to discover late. - id: no-exception-text-in-responses name: No exception text in HTTP responses entry: python -m pytest tests/probes/test_error_disclosure.py::test_no_exception_text_is_returned_to_callers -q language: system pass_filenames: false files: ^app/.*\.py$ description: > `detail=f"...{e}"` sends internal errors to the caller. It reached an unauthenticated endpoint once already. - id: transaction-discipline name: Route handlers do not commit entry: python -m pytest tests/probes/test_transaction_discipline.py -q language: system pass_filenames: false files: ^app/.*\.py$ description: > The request owns the transaction. A handler that commits splits one request into several and leaves partial state behind on failure. - id: layering name: Import layering contracts entry: lint-imports language: system pass_filenames: false files: ^app/.*\.py$ description: > routes → controllers → services → repositories → models, one direction only.