Spaces:
Running
Running
| """ | |
| SQL Validator -- chi cho phep cau SELECT (read-only), chan DROP/DELETE/INSERT/ | |
| UPDATE/ALTER/... Day la lop bao ve AN TOAN (khong cho sinh lenh nguy hiem), | |
| KHONG kiem tra SQL co tra loi DUNG cau hoi khong (model van co the sinh SELECT | |
| hop le nhung sai logic -- xem demo_app_pipeline_notes.md). | |
| """ | |
| import re | |
| import sqlglot | |
| import sqlglot.expressions as exp | |
| _FORBIDDEN_KEYWORDS = re.compile( | |
| r"\b(INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|TRUNCATE|ATTACH|DETACH|" | |
| r"PRAGMA|REPLACE|VACUUM|REINDEX)\b", | |
| re.IGNORECASE, | |
| ) | |
| def validate_sql(sql: str): | |
| """Return (is_safe: bool, message: str). Chi cho 1 cau SELECT/UNION duy nhat.""" | |
| if not sql or not sql.strip(): | |
| return False, "Model generated an empty SQL string." | |
| stripped = sql.strip().rstrip(";").strip() | |
| # Chan nhieu cau lenh xep chuoi (stacked queries qua ';') -- phong thu | |
| # ngay ca khi sqlglot co the parse duoc 1 phan cua chuoi. | |
| if ";" in stripped: | |
| return False, "Blocked: multiple statements separated by ';' are not allowed." | |
| if _FORBIDDEN_KEYWORDS.search(stripped): | |
| return False, "Blocked: only read-only SELECT queries are allowed." | |
| try: | |
| tree = sqlglot.parse_one(stripped, read="sqlite") | |
| except Exception as e: | |
| return False, f"Generated SQL failed to parse: {e}" | |
| if not isinstance(tree, (exp.Select, exp.Union)): | |
| return False, f"Blocked: only SELECT statements are allowed (got {type(tree).__name__})." | |
| return True, "OK" | |