Skip to content

Reject empty allowed_tables in SQLToolset instead of allowing all tables - #73381

Merged
kaxil merged 2 commits into
apache:mainfrom
ColtenOuO:fix-empty-allowed-tables
Sep 21, 2026
Merged

kaxil merged 2 commits into
apache:mainfrom
ColtenOuO:fix-empty-allowed-tables

Conversation

@ColtenOuO

@ColtenOuO ColtenOuO commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

SQLToolset(allowed_tables=[]) silently exposed every table in the schema to the agent. The constructor used frozenset(allowed_tables) if allowed_tables else None, so an empty list collapsed to None, which means "no restriction". An allow-list that resolves to nothing — a Variable.get, a YAML or config read, or a filtered comprehension in the Dag file — therefore disabled the guardrail entirely: list_tables returned every table, get_schema accepted any table, and query / check_query skipped allowed_tables enforcement. The toolset now fails fast with a clear ValueError instead. None keeps its documented meaning of "allow every table".

Changes

  • SQLToolset.__init__ raises ValueError when allowed_tables is an empty list.
  • Document the empty-list behaviour in the allowed_tables docstring and in the matching parameter list in docs/toolsets.rst.
  • Add a note under the Changelog header of providers/common/ai/docs/changelog.rst: allowed_tables=[] is accepted by 0.8.0 and 0.9.0, so a Dag that builds the list dynamically now fails at import instead of quietly allowing every table.
  • Add a unit test covering the new ValueError.

Was generative AI tooling used to co-author this PR?
  • Yes (Claude Code Opus 5)

@justinpakzad justinpakzad left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. The changes look good to me. This is technically a breaking change for anyone who previously passed an empty list (e.g. from a filtered list comprehension). Maybe worth a note in the change log. Will leave that up to a maintainer though since the commit subject that gets baked into the change log might be sufficient.

Comment thread providers/common/ai/src/airflow/providers/common/ai/toolsets/sql.py
Comment thread providers/common/ai/src/airflow/providers/common/ai/toolsets/sql.py
@kaxil

kaxil commented Sep 20, 2026

Copy link
Copy Markdown
Member

One note on the description, since it has no inline anchor: the summary gives "for example from a template or configuration" as how an empty allow-list arrives. Jinja cannot be the source here. toolsets is not in AgentOperator.template_fields (operators/agent.py:261-270), @task.agent re-exports that same list without adding to it (decorators/agent.py:61-64), and no toolset declares template_fields of its own, so nothing inside SQLToolset(...) is ever rendered.

The configuration half holds, though: a Variable.get or a YAML read in the Dag file can hand back []. Worth dropping the template example so the rationale rests on the path that can actually happen.

…ngelog

Rejecting an empty allowed_tables breaks construction that 0.8.0 and 0.9.0
accepted, so an upgrading Dag that builds the list dynamically now fails at
import and needs to be told that None is the way to ask for allow-all. The
toolsets page carries the same parameter list as the docstring and is where
users of this toolset land, so it has to describe the guard as well.
@ColtenOuO

Copy link
Copy Markdown
Contributor Author

All of the points are addressed in the pushed update.

Thanks for reviewing!

@ColtenOuO

ColtenOuO commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor Author

One note on the description, since it has no inline anchor: the summary gives "for example from a template or configuration" as how an empty allow-list arrives. Jinja cannot be the source here. toolsets is not in AgentOperator.template_fields (operators/agent.py:261-270), @task.agent re-exports that same list without adding to it (decorators/agent.py:61-64), and no toolset declares template_fields of its own, so nothing inside SQLToolset(...) is ever rendered.

The configuration half holds, though: a Variable.get or a YAML read in the Dag file can hand back []. Worth dropping the template example so the rationale rests on the path that can actually happen.

Yeah, I have checked them again and fixed the PR's description

Thanks for pointing that out!

@ColtenOuO
ColtenOuO requested a review from kaxil September 20, 2026 15:33
@kaxil
kaxil merged commit ae4343c into apache:main Sep 21, 2026
83 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants