Policy input
Each statement is prepared, not executed, and the policy receives what DuckDB says it does:
{ "user": "analyst", "roles": ["analyst"], "sql": "SELECT ...", "statement_type": "SELECT", "database": "sales", "tables": ["sales.main.orders"], "targets": [], "functions": ["range"], "databases": ["sales"], "resolved": true}| Field | |
|---|---|
user |
user name, API key name or OIDC user claim |
roles |
roles from the users file, token or identities |
sql |
statement text |
statement_type |
SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, EXPLAIN, PRAGMA… |
database |
catalog for unqualified names |
tables |
base tables read, views expanded |
targets |
objects written, created or dropped |
functions |
table functions used as sources |
databases |
catalogs touched by tables and targets |
resolved |
false when tables or targets could not be fully determined |
hidden_remote_scans |
lake scans behind views or macros |
Where the values come from
Section titled “Where the values come from”tablescome from DuckDB’s unoptimized logical plan, so joins,USING, CTEs, subqueries and views cannot hide a read.targetscome from a tokenizer, because DuckDB does not expose them. Secrets appear assecret:<name>and schemas asdb.schema.*.functionssuch asread_parquetbypass table grants; allow them explicitly.EXPLAIN ANALYZE <stmt>is authorized as<stmt>, since it executes.- External catalogs (Iceberg): for
SELECT, tables come from the parser’s syntax tree, respecting CTE scope. Other statements reading these catalogs arrive withresolved: false.
When resolved is false
Section titled “When resolved is false”Deny, unless the user is fully trusted. It is false when:
- the target of a write cannot be determined;
- the statement uses lexical constructs the tokenizer does not model exactly
like DuckDB (
$$...$$, nested comments,E'...'); - the statement type has no explicit handling (
CALL,VACUUM,COPY DATABASE…); - lake tables are read through a view or macro (
hidden_remote_scans > 0).