Skip to content

Refactor _grants_collect_schemas macro to accept schema_names and is_…#23

Open
jonhopper-dataengineers wants to merge 4 commits intomainfrom
feature/external_share_includes
Open

Refactor _grants_collect_schemas macro to accept schema_names and is_…#23
jonhopper-dataengineers wants to merge 4 commits intomainfrom
feature/external_share_includes

Conversation

@jonhopper-dataengineers
Copy link
Copy Markdown
Member

@jonhopper-dataengineers jonhopper-dataengineers commented Mar 23, 2026

…exclude_list parameters; update related grant macros for consistency and improved functionality

Pull Request Purpose

  • bug fix PR with no breaking changes — please ensure the base branch is main
  • new functionality — please ensure the base branch is the latest main branch
  • a breaking change — please ensure the base branch is the latest main branch

Description

refactor the _grants_collect_schemas macro to accept schema_names and is_exclude_list parameters, and updates related grant macros for consistency and improved functionality.

Notes for reviewer

Checklist

  • I have verified that these changes work locally via my sandbox
  • Added tests & descriptions to my macros (and models if applicable)
  • Pushed code into test
  • Updated the README.md (if applicable)
  • I have added an entry to CHANGELOG.md

Summary by Sourcery

Refactor schema collection and grant macros to support both include and exclude schema lists and add external share read-grant support.

New Features:

  • Introduce support in the grants schema collection macro for passing explicit schema name lists in addition to exclude lists.
  • Add a macro to grant external share read access on tables and views for specified schemas.

Enhancements:

  • Update existing grant-related macros to use the new schema collection signature for consistent behavior.
  • Bump the project version and document the new grants functionality in the changelog.

Documentation:

  • Add changelog entry describing the new schema collection behavior and external share read macro.

…exclude_list parameters; update related grant macros for consistency and improved functionality
…and add grant_external_share_read macro for schema permissions
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Mar 23, 2026

Reviewer's Guide

Refactors the core schema collection helper to support both include- and exclude-style schema lists and wires existing grant macros to the new interface, while adding a new macro to grant external share read access and bumping the project version and changelog.

Sequence diagram for new external share read grant macro using schema include list

sequenceDiagram
    participant Caller
    participant grant_internal_share_read_external as grant_internal_share_read
    participant grants_collect_schemas as _grants_collect_schemas
    participant Snowflake as Snowflake_DB

    Caller->>grant_internal_share_read_external: invoke(share_name, include_schemas, dry_run)
    grant_internal_share_read_external->>grant_internal_share_read_external: normalize include_schemas to list
    alt no schemas provided
        grant_internal_share_read_external->>Caller: return no schemas to grant
    else schemas provided
        grant_internal_share_read_external->>grants_collect_schemas: _grants_collect_schemas(include_schemas, false)
        grants_collect_schemas->>Snowflake: show schemas in database
        Snowflake-->>grants_collect_schemas: result set of schemas
        grants_collect_schemas->>grants_collect_schemas: filter schemas by include list
        grants_collect_schemas-->>grant_internal_share_read_external: list of valid schemas
        loop for each schema
            alt dry_run is true
                grant_internal_share_read_external->>Caller: log grant usage and select statements
            else dry_run is false
                grant_internal_share_read_external->>Snowflake: grant usage on schema to share
                grant_internal_share_read_external->>Snowflake: grant select on all tables in schema
                grant_internal_share_read_external->>Snowflake: show views in schema
                Snowflake-->>grant_internal_share_read_external: result set of views
                loop for each view
                    grant_internal_share_read_external->>Snowflake: grant select on view to share
                end
            end
        end
        grant_internal_share_read_external-->>Caller: finished granting
    end
Loading

Class diagram for updated grant macros and schema collection helper

classDiagram
    class grants_collect_schemas {
        <<macro>>
        _grants_collect_schemas(schema_names, is_exclude_list=true)
        +list include_schemas
    }

    class grant_internal_share_read_external {
        <<macro>>
        grant_internal_share_read(share_name, include_schemas, dry_run=false)
    }

    class grant_internal_share_read_existing {
        <<macro>>
        grant_internal_share_read(share_name, exclude_schemas, dry_run=false)
    }

    class grant_procedure_usage {
        <<macro>>
        grant_schema_procedure_usage(exclude_schemas, grant_roles)
    }

    class grant_schema_monitor {
        <<macro>>
        grant_schema_monitor(exclude_schemas, grant_roles)
    }

    class grant_schema_operate {
        <<macro>>
        grant_schema_operate(exclude_schemas, grant_roles)
    }

    class grant_schema_ownership {
        <<macro>>
        grant_schema_ownership(exclude_schemas, grant_roles)
    }

    class grant_schema_read {
        <<macro>>
        grant_schema_read(exclude_schemas, grant_roles)
    }

    class grant_semantic_views_privileges {
        <<macro>>
        grant_semantic_views_privileges(exclude_schemas, grant_roles)
    }

    grants_collect_schemas <.. grant_internal_share_read_existing : uses
    grants_collect_schemas <.. grant_internal_share_read_external : uses
    grants_collect_schemas <.. grant_procedure_usage : uses
    grants_collect_schemas <.. grant_schema_monitor : uses
    grants_collect_schemas <.. grant_schema_operate : uses
    grants_collect_schemas <.. grant_schema_ownership : uses
    grants_collect_schemas <.. grant_schema_read : uses
    grants_collect_schemas <.. grant_semantic_views_privileges : uses

    grant_internal_share_read_existing : +share_name
    grant_internal_share_read_existing : +exclude_schemas
    grant_internal_share_read_existing : +dry_run

    grant_internal_share_read_external : +share_name
    grant_internal_share_read_external : +include_schemas
    grant_internal_share_read_external : +dry_run

    grants_collect_schemas : +schema_names
    grants_collect_schemas : +is_exclude_list
Loading

Flow diagram for refactored _grants_collect_schemas macro behavior

flowchart TD
    A["start _grants_collect_schemas(schema_names, is_exclude_list)"] --> B{schema_names is iterable}
    B -- no --> C[set schema_names to empty list]
    B -- yes --> D[keep schema_names as provided]
    C --> E{is_exclude_list is true and INFORMATION_SCHEMA not in schema_names}
    D --> E
    E -- yes --> F[append INFORMATION_SCHEMA to schema_names]
    E -- no --> G[do not modify schema_names]
    F --> H[run query: show schemas in target.database]
    G --> H
    H --> I{execute and results present}
    I -- no --> J[return empty include_schemas]
    I -- yes --> K[loop over each row in results]
    K --> L{row.name already in include_schemas}
    L -- yes --> K
    L -- no --> M{is_exclude_list is true}
    M -- yes --> N{row.name not in schema_names}
    N -- yes --> O[append row.name to include_schemas]
    N -- no --> K
    M -- no --> P{row.name in schema_names}
    P -- yes --> O
    P -- no --> K
    O --> K
    K --> Q[loop complete]
    Q --> R[return include_schemas]
Loading

File-Level Changes

Change Details Files
Refactor schema collection helper to support include/exclude modes.
  • Change _grants_collect_schemas signature to accept schema_names and is_exclude_list flag with default true.
  • Normalize schema_names input to an iterable list and always ensure INFORMATION_SCHEMA is added when using exclude mode.
  • Adjust loop logic to include schemas based on either exclusion (not in schema_names) or inclusion (in schema_names) depending on is_exclude_list.
macros/grants/_helpers.sql
Update existing grant macros to use the new helper interface in exclude mode.
  • Pass exclude_schemas into _grants_collect_schemas along with is_exclude_list=true in all existing grant macros that previously relied on exclusion-only behavior.
  • Keep local logic that appends INFORMATION_SCHEMA to exclude_schemas where it already exists, maintaining effective behavior.
macros/grants/grant_internal_share_read.sql
macros/grants/grant_procedure_usage.sql
macros/grants/grant_schema_monitor.sql
macros/grants/grant_schema_operate.sql
macros/grants/grant_schema_ownership.sql
macros/grants/grant_schema_read.sql
macros/grants/grant_semantic_views_privileges.sql
Introduce macro to grant read access to an external share using an include list of schemas.
  • Add grant_internal_share_read macro that normalizes include_schemas (handles none, string, non-iterable) and returns early if empty.
  • Use _grants_collect_schemas with is_exclude_list=false to resolve the final set of schemas from the include list.
  • For each resolved schema, grant USAGE on the schema and SELECT on all tables plus individual SELECT grants on each view, honoring dry_run by logging instead of executing queries.
macros/grants/grant_external_share_read.sql
Bump project version and document the new functionality.
  • Update dbt_project.yml version from 0.3.10 to 0.3.11.
  • Add a changelog entry for v0.3.11 describing the refactor of _grants_collect_schemas and the new external share read macro.
dbt_project.yml
CHANGELOG.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • The new macros/grants/grant_external_share_read.sql file defines a macro named grant_internal_share_read, which both mismatches the file/feature intent (external share) and collides with the existing internal-share macro name; consider renaming the macro to something like grant_external_share_read and ensuring no name collisions.
  • Several callers (e.g. grant_schema_read, grant_schema_monitor, etc.) still manually append INFORMATION_SCHEMA to exclude_schemas even though _grants_collect_schemas now enforces this when is_exclude_list=true; you could simplify those call sites by removing the redundant INFORMATION_SCHEMA handling.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `macros/grants/grant_external_share_read.sql` file defines a macro named `grant_internal_share_read`, which both mismatches the file/feature intent (external share) and collides with the existing internal-share macro name; consider renaming the macro to something like `grant_external_share_read` and ensuring no name collisions.
- Several callers (e.g. `grant_schema_read`, `grant_schema_monitor`, etc.) still manually append `INFORMATION_SCHEMA` to `exclude_schemas` even though `_grants_collect_schemas` now enforces this when `is_exclude_list=true`; you could simplify those call sites by removing the redundant `INFORMATION_SCHEMA` handling.

## Individual Comments

### Comment 1
<location path="macros/grants/grant_external_share_read.sql" line_range="1" />
<code_context>
+{% macro grant_internal_share_read(share_name, include_schemas, dry_run=false) %}
+  {% if flags.WHICH in ['run', 'run-operation'] %}
+    {% if execute %}
</code_context>
<issue_to_address>
**issue (bug_risk):** Macro name and file name are mismatched and appear to duplicate an existing macro, which is likely to override the original implementation.

This file is named `grant_external_share_read.sql` but defines `grant_internal_share_read`, which already exists in `macros/grants/grant_internal_share_read.sql`. In dbt the last definition wins, so this will silently override the original. Please either rename this macro (e.g. to `grant_external_share_read`) or consolidate the logic to avoid unexpected overrides and ambiguity about which implementation is used.
</issue_to_address>

### Comment 2
<location path="macros/grants/_helpers.sql" line_range="10-19" />
<code_context>
 #}

-{% macro _grants_collect_schemas(exclude_schemas) %}
+{% macro _grants_collect_schemas(schema_names, is_exclude_list=true) %}
     {% set include_schemas = [] %}
-    {% if exclude_schemas is not iterable %}
</code_context>
<issue_to_address>
**suggestion:** Callers and helper both manage `INFORMATION_SCHEMA` in exclude mode, leading to duplicated responsibility.

The new `is_exclude_list` flag makes `_grants_collect_schemas` append `INFORMATION_SCHEMA` for exclude lists, but some callers (e.g. `grant_*` macros) still append it before calling `_grants_collect_schemas(..., is_exclude_list=true)`. Even though double-insertion is avoided, the responsibility for excluding `INFORMATION_SCHEMA` is now split. It would be clearer to handle this in a single place (either only in `_grants_collect_schemas` or only in the callers).

Suggested implementation:

```
These ideas intentionally deferred to keep current refactor incremental.
#}

-- NOTE:
-- Responsibility for excluding INFORMATION_SCHEMA is centralized here.
-- Callers MUST NOT add "INFORMATION_SCHEMA" to schema_names themselves when
-- using exclude-mode; instead, pass only the user-specified schemas and
-- rely on this helper to append INFORMATION_SCHEMA when is_exclude_list is true.
{% macro _grants_collect_schemas(schema_names, is_exclude_list=true) %}
    {% set include_schemas = [] %}
    {% if schema_names is not iterable %}
        {% set schema_names = [] %}
    {% endif %}
    {% if is_exclude_list and "INFORMATION_SCHEMA" not in schema_names %}
        {% do schema_names.append("INFORMATION_SCHEMA") %}
    {% endif %}
    {% set query %}

```

To fully implement the suggestion and avoid duplicated responsibility:

1. Find all callers of `_grants_collect_schemas` (for example, in `grant_*` macros in the grants-related SQL macro files).
2. In exclude-mode callers (where `is_exclude_list` is `true` or omitted to use the default), remove any manual appending of `"INFORMATION_SCHEMA"` to the schema list before calling `_grants_collect_schemas`.
   - e.g. change patterns like:
     - `{% set exclude_schemas = exclude_schemas + ["INFORMATION_SCHEMA"] %}`
     - or `{% do exclude_schemas.append("INFORMATION_SCHEMA") %}`
     before `_grants_collect_schemas(exclude_schemas, is_exclude_list=true)`
     so that `"INFORMATION_SCHEMA"` is no longer added explicitly.
3. Ensure include-mode callers (where `is_exclude_list` is `false`) do not rely on this helper to manage `"INFORMATION_SCHEMA"`; they should pass the exact include list they want.
</issue_to_address>

### Comment 3
<location path="CHANGELOG.md" line_range="6" />
<code_context>

+## v0.3.11 - 2026-03-24 - External Share Permissions
+
+- refactor the _grants_collect_schemas macro to accept schema_names and is_exclude_list parameters, and updates related grant macros for consistency and improved functionality.
+- added new macro `grant_external_share_read`  to apply `select` permissions on all tables and views for specified schemas
+
</code_context>
<issue_to_address>
**suggestion (typo):** Align verb forms in this sentence for correct grammar.

The phrase "refactor ... and updates" mixes verb forms. Please use a consistent tense, e.g., "refactors ... and updates" or "refactored ... and updated."

```suggestion
- refactored the _grants_collect_schemas macro to accept schema_names and is_exclude_list parameters, and updated related grant macros for consistency and improved functionality.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -0,0 +1,57 @@
{% macro grant_internal_share_read(share_name, include_schemas, dry_run=false) %}
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.

issue (bug_risk): Macro name and file name are mismatched and appear to duplicate an existing macro, which is likely to override the original implementation.

This file is named grant_external_share_read.sql but defines grant_internal_share_read, which already exists in macros/grants/grant_internal_share_read.sql. In dbt the last definition wins, so this will silently override the original. Please either rename this macro (e.g. to grant_external_share_read) or consolidate the logic to avoid unexpected overrides and ambiguity about which implementation is used.

Comment on lines +10 to 19
{% macro _grants_collect_schemas(schema_names, is_exclude_list=true) %}
{% set include_schemas = [] %}
{% if exclude_schemas is not iterable %}
{% set exclude_schemas = [] %}
{% if schema_names is not iterable %}
{% set schema_names = [] %}
{% endif %}
{% if "INFORMATION_SCHEMA" not in exclude_schemas %}
{% do exclude_schemas.append("INFORMATION_SCHEMA") %}
{% if "INFORMATION_SCHEMA" not in schema_names and is_exclude_list %}
{% do schema_names.append("INFORMATION_SCHEMA") %}
{% endif %}
{% set query %}
show schemas in database {{ target.database }};
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.

suggestion: Callers and helper both manage INFORMATION_SCHEMA in exclude mode, leading to duplicated responsibility.

The new is_exclude_list flag makes _grants_collect_schemas append INFORMATION_SCHEMA for exclude lists, but some callers (e.g. grant_* macros) still append it before calling _grants_collect_schemas(..., is_exclude_list=true). Even though double-insertion is avoided, the responsibility for excluding INFORMATION_SCHEMA is now split. It would be clearer to handle this in a single place (either only in _grants_collect_schemas or only in the callers).

Suggested implementation:

These ideas intentionally deferred to keep current refactor incremental.
#}

-- NOTE:
-- Responsibility for excluding INFORMATION_SCHEMA is centralized here.
-- Callers MUST NOT add "INFORMATION_SCHEMA" to schema_names themselves when
-- using exclude-mode; instead, pass only the user-specified schemas and
-- rely on this helper to append INFORMATION_SCHEMA when is_exclude_list is true.
{% macro _grants_collect_schemas(schema_names, is_exclude_list=true) %}
    {% set include_schemas = [] %}
    {% if schema_names is not iterable %}
        {% set schema_names = [] %}
    {% endif %}
    {% if is_exclude_list and "INFORMATION_SCHEMA" not in schema_names %}
        {% do schema_names.append("INFORMATION_SCHEMA") %}
    {% endif %}
    {% set query %}

To fully implement the suggestion and avoid duplicated responsibility:

  1. Find all callers of _grants_collect_schemas (for example, in grant_* macros in the grants-related SQL macro files).
  2. In exclude-mode callers (where is_exclude_list is true or omitted to use the default), remove any manual appending of "INFORMATION_SCHEMA" to the schema list before calling _grants_collect_schemas.
    • e.g. change patterns like:
      • {% set exclude_schemas = exclude_schemas + ["INFORMATION_SCHEMA"] %}
      • or {% do exclude_schemas.append("INFORMATION_SCHEMA") %}
        before _grants_collect_schemas(exclude_schemas, is_exclude_list=true)
        so that "INFORMATION_SCHEMA" is no longer added explicitly.
  3. Ensure include-mode callers (where is_exclude_list is false) do not rely on this helper to manage "INFORMATION_SCHEMA"; they should pass the exact include list they want.

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.

1 participant