Skip to content

Support Snowflake Cortex permissions: DRG fetch fix + USE AI FUNCTIONS + CORTEX SEARCH SERVICE grants#18

Merged
noel merged 3 commits into
datacoves:mainfrom
usbrandon:cortex-support
May 20, 2026
Merged

Support Snowflake Cortex permissions: DRG fetch fix + USE AI FUNCTIONS + CORTEX SEARCH SERVICE grants#18
noel merged 3 commits into
datacoves:mainfrom
usbrandon:cortex-support

Conversation

@usbrandon
Copy link
Copy Markdown
Contributor

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_grant returning the wrong row (commit)

A database role granted to multiple grantees (e.g. SNOWFLAKE.CORTEX_USER is granted to ACCOUNTADMIN, PUBLIC, and any custom role) cannot be modeled correctly because fetch_database_role_grant filters role_grants by the requested grantee but then returns show_result[0] — the unfiltered first row. Every per-grantee fetch returns the same data (the first SHOW GRANTS OF DATABASE ROLE row), so declaring a second grantee in YAML produces a spurious UpdateResource(to_role: ACCOUNTADMIN → DBT_DEVELOPER) diff instead of a clean CreateResource. There is no update_database_role_grant lifecycle hook, so applying that update emits invalid ALTER 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 FUNCTIONS to AccountPriv (same commit)

Per Snowflake's Cortex AI SQL docs, Cortex AI functions require the account-level privilege USE AI FUNCTIONS in addition to a database role (SNOWFLAKE.CORTEX_USER or SNOWFLAKE.AI_FUNCTIONS_USER). It is granted to PUBLIC by default, but declarative management requires it in the enum to parse priv: USE AI FUNCTIONS / on: account / to: <role> from YAML. Added as AccountPriv.USE_AI_FUNCTIONS.

3. Add CORTEX SEARCH SERVICE as a grantable resource type (commit)

Cortex Search is a schema-scoped service with USAGE (query the service), MONITOR (access AI observability logs), and OWNERSHIP privileges. Users naturally want to write priv: USAGE on cortex search service db.sch.svc / to: r in YAML — but CORTEX SEARCH SERVICE wasn't in ResourceType and had no Priv enum, so the parser rejected those grants.

Following the precedent set by the generic INTEGRATION umbrella scope (introduced earlier in this fork): adds ResourceType.CORTEX_SEARCH_SERVICE, CortexSearchServicePriv(ALL/USAGE/MONITOR/OWNERSHIP), a PRIVS_FOR_RESOURCE_TYPE mapping, and a SchemaScope() registration in RESOURCE_SCOPES. No concrete CortexSearchService resource 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 SERVICE from the "Skip undocumented privs" filter in list_grants — that privilege is already in SchemaPriv and 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 failed
  • New unit tests for AccountPriv.USE_AI_FUNCTIONS, CortexSearchServicePriv enum values, and Grant(priv=USAGE, on cortex search service ...) SQL rendering
  • New integration test (test_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 regression
  • Live validation against a real account: calling fetch_database_role_grant against SNOWFLAKE.CORTEX_USER (granted to ACCOUNTADMIN, DBT_DEVELOPER, PUBLIC in that account) — each grantee URN now returns its own to_role. Before the fix, all three returned ACCOUNTADMIN's row.
  • End-to-end snowcap plan against a real account: previously emitted ~ UPDATE: CORTEX_USER to_role ACCOUNTADMIN → DBT_DEVELOPER whenever the YAML added a second grantee; now emits a clean 0 to update plan.

References

🤖 Generated with Claude Code

usbrandon and others added 3 commits May 17, 2026 14:41
…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>
@noel
Copy link
Copy Markdown
Contributor

noel commented May 20, 2026

Thanks for the contribution. I will merge this

@noel noel merged commit 56db5e4 into datacoves:main May 20, 2026
4 checks passed
@usbrandon usbrandon deleted the cortex-support branch May 22, 2026 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants