pavansai1997 opened a new issue, #76229:
URL: https://github.com/apache/airflow/issues/76229

   ### Description
   
   Add an opt-in `allowed_tables` parameter to `LLMSQLQueryOperator` (and 
`@task.llm_sql`) that rejects generated SQL referencing any table outside the 
list, reusing the enforcement `SQLToolset(allowed_tables=...)` already has.
   
   Today `table_names` only selects which schemas are put into the model's 
context, and `validate_sql` only checks the statement type. Nothing checks 
which tables the generated query reads. With
   
   ```python
   LLMSQLQueryOperator(
       task_id="report",
       prompt="Total order value per customer last month",
       llm_conn_id="my_llm",
       table_names=["orders"],
       schema_context="orders(customer_id int, amount numeric, created_at 
date)",
   )
   ```
   
   a model that returns `SELECT name, salary FROM employee_salaries` passes 
validation and the query is handed to the downstream task unchanged (verified 
on `main` with a stubbed model returning that query).
   
   The same provider already solves this for agents: 
`SQLToolset(allowed_tables=[...])` resolves every table a query reaches through 
`collect_table_references` (CTE scoping, subqueries, catalog qualification) and 
refuses constructs it cannot verify, such as table-valued functions and unknown 
functions. That check is not available to `LLMSQLQueryOperator`.
   
   ### Use case/motivation
   
   `LLMSQLQueryOperator` turns free text into SQL that a downstream task 
executes, often with a database user that can read more than the tables the 
pipeline is meant for. Restricting the generated query to known tables limits 
what a confused model or a prompt-injected input can reach, as defence in depth 
next to least-privilege grants (the same caveat `agent_security.rst` gives for 
`SQLToolset`'s allow-list). Users of `SQLToolset` already get this check; users 
of the single-shot operator cannot express it.
   
   Proposed behaviour, aligned with `SQLToolset` so both paths enforce the same 
rules:
   
   - `allowed_tables: list[str] | None = None`. `None` keeps today's behaviour, 
so the change is opt-in and backward compatible.
   - Matching follows `SQLToolset`: case-insensitive, an unqualified entry 
matches unqualified references, a `schema.table` entry matches that qualified 
reference, and catalog-qualified references are refused. An empty list raises 
instead of meaning "no restriction".
   - The check runs on the generated SQL and again on SQL edited by a reviewer 
in the approval flow, next to the existing statement-type validation, and 
raises `SQLSafetyError`.
   - `allowed_tables` together with `validate_sql=False` raises at construction 
rather than silently skipping the check.
   
   Implementation-wise, the table-reference comparison would move out of 
`SQLToolset` into a helper in `utils/sql_validation.py` used by both, so there 
is one implementation of the rules. `SQLToolset` behaviour would stay unchanged.
   
   ### Related issues
   
   None found.
   
   ### Are you willing to submit a PR?
   
   - [X] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [X] I agree to follow this project's Code of Conduct
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to