Support Snowflake Cortex permissions: DRG fetch fix + USE AI FUNCTIONS + CORTEX SEARCH SERVICE grants#18
Merged
Merged
Conversation
…priv Two related fixes that together unlock modeling Snowflake Cortex permissions in snowcap. 1. fetch_database_role_grant returned show_result[0] (unfiltered first row of SHOW GRANTS) instead of role_grants[0] (the row matching the URN's requested grantee). For any database role granted to multiple account/database roles, every per-grantee fetch returned the first grantee's data — causing the diff engine to emit a spurious UpdateResource (e.g. "to_role: ACCOUNTADMIN -> DBT_DEVELOPER") whenever a second grantee was declared in YAML. There is no update_database_role_grant lifecycle hook so the apply would also fail with invalid SQL. Adds an integration regression test (test_fetch_grant_of_database_role_multiple_grantees) that grants one database role to two account roles and fetches each FQN separately; previously both fetches returned the same first-grantee row. 2. Adds USE_AI_FUNCTIONS = "USE AI FUNCTIONS" to AccountPriv. This account- level privilege gates Snowflake Cortex AI SQL functions (AI_COMPLETE, AI_FILTER, SUMMARIZE, COMPLETE, embed/search REST APIs, etc.). Without it in the enum, `priv: USE AI FUNCTIONS / on: account` in YAML raises a parse error. Together these enable native modeling of Cortex Code, Cortex AI SQL, and Cortex Agents access in YAML via `database_role_grants` (CORTEX_USER, CORTEX_AGENT_USER, COPILOT_USER, AI_FUNCTIONS_USER) and `grants` (USE AI FUNCTIONS on account). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds CORTEX SEARCH SERVICE as a schema-scoped grantable resource type so
users can write:
grants:
- priv: USAGE
on: cortex search service <db>.<schema>.<svc>
to: <role>
- priv: MONITOR
on: cortex search service <db>.<schema>.<svc>
to: <observability_role>
Snowflake's Cortex Search Service supports four privileges (USAGE,
MONITOR, OWNERSHIP, ALL); USAGE is required to run
SNOWFLAKE.CORTEX.SEARCH_PREVIEW and MONITOR is required for the new
get_ai_observability_events() log access. The schema-scope priv
CREATE CORTEX SEARCH SERVICE was already in SchemaPriv.
Changes:
- ResourceType.CORTEX_SEARCH_SERVICE added to the enum (alphabetical).
- CortexSearchServicePriv(Priv) class with ALL/USAGE/MONITOR/OWNERSHIP.
- PRIVS_FOR_RESOURCE_TYPE entry mapping the type to the priv class.
- RESOURCE_SCOPES entry registering SchemaScope() (following the
INTEGRATION precedent: no concrete resource class yet, just enough to
let `priv: ... on: cortex search service ...` parse and render).
- data_provider.list_grants: drop CREATE CORTEX SEARCH SERVICE from the
"Skip undocumented privs" filter — it is documented (in SchemaPriv)
and should round-trip via list_grants like any other schema priv.
CANCEL QUERY remains in the skip list (genuinely unmodeled).
- Unit tests covering the priv enum values and end-to-end Grant SQL
rendering for both USAGE and MONITOR.
Full Cortex Search Service resource modeling (CREATE ... AS <query>,
embedding model, target_lag, attributes) is left for a future PR — this
change just covers grants.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address documentation needs for the Cortex permission support added in this PR. Follows the pattern set by PR datacoves#16 (Iceberg REST Catalog Integration docs) per @noel's previous feedback — a resource-specific docs page with YAML + Python examples and a "Minimal example" section covering real-world gotchas. - docs/resources/cortex_search_service.md (new): grant patterns for CORTEX SEARCH SERVICE (USAGE, MONITOR), plus a complete worked example wiring up Cortex Code + Cortex AI SQL + Cortex Search access for a single role. Documents the PUBLIC-default behavior of CORTEX_USER and the explicit-grant requirement for COPILOT_USER, the database-role + account-priv layering, and the multi-grantee fetch prerequisite (this PR). - docs/resources/grant.md: add USE AI FUNCTIONS on ACCOUNT and USAGE/MONITOR on CORTEX SEARCH SERVICE to the Object Grants YAML example. - mkdocs.yml: register CortexSearchService under a new "AI" nav group alongside Access Control. Sets a place for future AI/Cortex resource pages (Cortex Search Service body modeling, semantic views, etc.) without bloating "Integrations" or "Access Control". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
|
Thanks for the contribution. I will merge this |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds native modeling for Snowflake Cortex permissions in snowcap YAML, addressing three related gaps surfaced while trying to manage Cortex Code and Cortex AI access for a dbt developer role.
1. Fix
fetch_database_role_grantreturning the wrong row (commit)A database role granted to multiple grantees (e.g.
SNOWFLAKE.CORTEX_USERis granted toACCOUNTADMIN,PUBLIC, and any custom role) cannot be modeled correctly becausefetch_database_role_grantfiltersrole_grantsby the requested grantee but then returnsshow_result[0]— the unfiltered first row. Every per-grantee fetch returns the same data (the firstSHOW GRANTS OF DATABASE ROLErow), so declaring a second grantee in YAML produces a spuriousUpdateResource(to_role: ACCOUNTADMIN → DBT_DEVELOPER)diff instead of a cleanCreateResource. There is noupdate_database_role_grantlifecycle hook, so applying that update emits invalidALTER DATABASE_ROLE_GRANT ... SET to_role ...SQL.The fix is a one-line change in
snowcap/data_provider.py(data = show_result[0]→data = role_grants[0]). An integration regression test (test_fetch_grant_of_database_role_multiple_grantees) creates one database role, grants it to two account roles, and fetches each grantee independently — which previously returned identical data.2. Add
USE AI FUNCTIONStoAccountPriv(same commit)Per Snowflake's Cortex AI SQL docs, Cortex AI functions require the account-level privilege
USE AI FUNCTIONSin addition to a database role (SNOWFLAKE.CORTEX_USERorSNOWFLAKE.AI_FUNCTIONS_USER). It is granted toPUBLICby default, but declarative management requires it in the enum to parsepriv: USE AI FUNCTIONS / on: account / to: <role>from YAML. Added asAccountPriv.USE_AI_FUNCTIONS.3. Add
CORTEX SEARCH SERVICEas a grantable resource type (commit)Cortex Search is a schema-scoped service with
USAGE(query the service),MONITOR(access AI observability logs), andOWNERSHIPprivileges. Users naturally want to writepriv: USAGE on cortex search service db.sch.svc / to: rin YAML — butCORTEX SEARCH SERVICEwasn't inResourceTypeand had noPrivenum, so the parser rejected those grants.Following the precedent set by the generic
INTEGRATIONumbrella scope (introduced earlier in this fork): addsResourceType.CORTEX_SEARCH_SERVICE,CortexSearchServicePriv(ALL/USAGE/MONITOR/OWNERSHIP), aPRIVS_FOR_RESOURCE_TYPEmapping, and aSchemaScope()registration inRESOURCE_SCOPES. No concreteCortexSearchServiceresource class — full DDL modeling (CREATE CORTEX SEARCH SERVICE ... AS <query>with embedding model and target_lag) is left for a separate PR; this change covers grants only.Also drops
CREATE CORTEX SEARCH SERVICEfrom the "Skip undocumented privs" filter inlist_grants— that privilege is already inSchemaPrivand should round-trip like any other documented priv.CANCEL QUERY(genuinely undocumented) stays filtered.Test plan
uv run pytest tests/ --ignore=tests/integration -q→ 1498 passed, 0 failedAccountPriv.USE_AI_FUNCTIONS,CortexSearchServicePrivenum values, andGrant(priv=USAGE, on cortex search service ...)SQL renderingtest_fetch_grant_of_database_role_multiple_grantees) creating one database role granted to two account roles and verifying each fetch returns its own grantee — would have caught the regressionfetch_database_role_grantagainstSNOWFLAKE.CORTEX_USER(granted toACCOUNTADMIN,DBT_DEVELOPER,PUBLICin that account) — each grantee URN now returns its ownto_role. Before the fix, all three returnedACCOUNTADMIN's row.snowcap planagainst a real account: previously emitted~ UPDATE: CORTEX_USER to_role ACCOUNTADMIN → DBT_DEVELOPERwhenever the YAML added a second grantee; now emits a clean0 to updateplan.References
🤖 Generated with Claude Code