diff --git a/dbt-bigquery/.changes/unreleased/Fixes-20250202-105422.yaml b/dbt-bigquery/.changes/unreleased/Fixes-20250202-105422.yaml new file mode 100644 index 000000000..af8c00760 --- /dev/null +++ b/dbt-bigquery/.changes/unreleased/Fixes-20250202-105422.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Fix silently ignoring materialized view authorization +time: 2025-02-02T10:54:22.12198+01:00 +custom: + Author: kubikb + Issue: "1471" diff --git a/dbt-bigquery/src/dbt/include/bigquery/macros/materializations/materialized_view.sql b/dbt-bigquery/src/dbt/include/bigquery/macros/materializations/materialized_view.sql new file mode 100644 index 000000000..0b305cc5b --- /dev/null +++ b/dbt-bigquery/src/dbt/include/bigquery/macros/materializations/materialized_view.sql @@ -0,0 +1,13 @@ +{% materialization materialized_view, adapter='bigquery' -%} + + {% set relations = materialization_materialized_view_default() %} + + {% if config.get('grant_access_to') %} + {% for grant_target_dict in config.get('grant_access_to') %} + {% do adapter.grant_access_to(this, 'view', None, grant_target_dict) %} + {% endfor %} + {% endif %} + + {{ return(relations) }} + +{%- endmaterialization %} diff --git a/dbt-bigquery/tests/functional/adapter/test_grant_access_to.py b/dbt-bigquery/tests/functional/adapter/test_grant_access_to.py index 633cebe92..57edd13f8 100644 --- a/dbt-bigquery/tests/functional/adapter/test_grant_access_to.py +++ b/dbt-bigquery/tests/functional/adapter/test_grant_access_to.py @@ -21,6 +21,24 @@ def select_1(dataset: str, materialized: str): ) +def select_1_materialized_view(dataset: str): + config = f"""config( + materialized='materialized_view', + grant_access_to=[ + {{'project': 'dbt-test-env', 'dataset': '{dataset}'}}, + ] + )""" + return ( + "{{" + + config + + "}}" + + """ + SELECT one, COUNT(1) AS count_one + FROM {{ ref('select_1_table') }} + GROUP BY one""" + ) + + BAD_CONFIG_TABLE_NAME = "bad_view" BAD_CONFIG_TABLE = """ {{ config( @@ -75,16 +93,35 @@ def models(self, unique_schema): return { "select_1.sql": select_1(dataset=dataset, materialized="view"), "select_1_table.sql": select_1(dataset=dataset, materialized="table"), + "select_1_materialized_view.sql": select_1_materialized_view(dataset=dataset), } - def test_grant_access_succeeds(self, project, setup_grant_schema, teardown_grant_schema): + def test_grant_access_succeeds( + self, project, setup_grant_schema, teardown_grant_schema, unique_schema + ): # Need to run twice to validate idempotency results = run_dbt(["run"]) - assert len(results) == 2 + assert len(results) == 3 time.sleep(10) - results = run_dbt(["run"]) + # Materialized view excluded since it would produce an error since source table is replaced + results = run_dbt(["run", "--exclude", "select_1_materialized_view"]) assert len(results) == 2 + with project.adapter.connection_named("__test_grants"): + client = project.adapter.connections.get_thread_connection().handle + dataset_name = get_schema_name(unique_schema) + dataset_id = "{}.{}".format("dbt-test-env", dataset_name) + bq_dataset = client.get_dataset(dataset_id) + + authorized_view_names = [] + for access_entry in bq_dataset.access_entries: + if access_entry.entity_type != "view": + continue + + authorized_view_names.append(access_entry.entity_id["tableId"]) + + assert set(authorized_view_names) == set(["select_1", "select_1_materialized_view"]) + class TestAccessGrantFails: @pytest.fixture(scope="class")