corrective-rag-data-assistant / app /sql /sql_validator.py
nvikou's picture
Upgrade CRAG: embeddings, SQL SQLite, pro UI, 60-eval, local data
98aa813 verified
Raw History Blame Contribute Delete
1.43 kB
"""Validation SQL en lecture seule (règles Rag_crag.md)."""
from __future__ import annotations
import re
FORBIDDEN_SQL = {
"INSERT", "UPDATE", "DELETE", "DROP",
"ALTER", "TRUNCATE", "CREATE", "EXEC",
"EXECUTE", "GRANT", "REVOKE", "MERGE",
"ATTACH", "DETACH", "PRAGMA", "VACUUM",
"REPLACE", "INTO",
}
ALLOWED_TABLES = {"sales"}
ALLOWED_COLUMNS = {
"client", "produit", "region", "mois", "trimestre",
"chiffre_affaires", "marge",
}
ALLOWED_AGGREGATIONS = {"SUM", "MAX", "MIN", "AVG", "COUNT"}
MAX_ROWS = 100
def is_safe_sql(query: str) -> bool:
"""Refuse tout SQL non-SELECT ou contenant un mot-clé interdit."""
normalized = query.upper().strip()
if not normalized.startswith("SELECT"):
return False
if ";" in normalized.rstrip(";"):
return False
tokens = set(re.findall(r"[A-Z_]+", normalized))
return not any(keyword in tokens for keyword in FORBIDDEN_SQL)
def assert_whitelisted_identifiers(
table: str,
columns: list[str],
aggregation: str | None = None,
) -> None:
if table not in ALLOWED_TABLES:
raise ValueError(f"Table non autorisée: {table}")
for col in columns:
if col not in ALLOWED_COLUMNS:
raise ValueError(f"Colonne non autorisée: {col}")
if aggregation is not None and aggregation.upper() not in ALLOWED_AGGREGATIONS:
raise ValueError(f"Agrégation non autorisée: {aggregation}")