Skip to content

Commit 40b25fb

Browse files
committed
Fix seeds grants tests
1 parent 267d040 commit 40b25fb

4 files changed

Lines changed: 137 additions & 16 deletions

File tree

dbt/include/dremio/macros/adapters/apply_grants.sql

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,48 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
See the License for the specific language governing permissions and
1313
limitations under the License.*/
1414

15+
{% macro dremio__apply_grants(relation, grant_config, should_revoke=True) %}
16+
{#-- If grant_config is {} or None, this is a no-op --#}
17+
{% if grant_config %}
18+
{#-- ensure grant have a prefix, defaults to user if not provided --#}
19+
{% for privilege, grantees in grant_config.items() %}
20+
{% set updated_grantees = [] %}
21+
{% for grantee in grantees %}
22+
{% if ':' not in grantee %}
23+
{% do updated_grantees.append('user:' ~ grantee) %}
24+
{% else %}
25+
{% do updated_grantees.append(grantee) %}
26+
{% endif %}
27+
{% endfor %}
28+
{% do grant_config.update({privilege: updated_grantees}) %}
29+
{% endfor %}
30+
{% if should_revoke %}
31+
{#-- We think previous grants may have carried over --#}
32+
{#-- Show current grants and calculate diffs --#}
33+
{% set current_grants_table = run_query(get_show_grant_sql(relation)) %}
34+
{% set current_grants_dict = adapter.standardize_grants_dict(current_grants_table) %}
35+
{% set needs_granting = diff_of_two_dicts(grant_config, current_grants_dict) %}
36+
{% set needs_revoking = diff_of_two_dicts(current_grants_dict, grant_config) %}
37+
{% if not (needs_granting or needs_revoking) %}
38+
{{ log('On ' ~ relation.render() ~': All grants are in place, no revocation or granting needed.')}}
39+
{% endif %}
40+
{% else %}
41+
{#-- We don't think there's any chance of previous grants having carried over. --#}
42+
{#-- Jump straight to granting what the user has configured. --#}
43+
{% set needs_revoking = {} %}
44+
{% set needs_granting = grant_config %}
45+
{% endif %}
46+
{% if needs_granting or needs_revoking %}
47+
{% set revoke_statement_list = get_dcl_statement_list(relation, needs_revoking, get_revoke_sql) %}
48+
{% set grant_statement_list = get_dcl_statement_list(relation, needs_granting, get_grant_sql) %}
49+
{% set dcl_statement_list = revoke_statement_list + grant_statement_list %}
50+
{% if dcl_statement_list %}
51+
{{ call_dcl_statements(dcl_statement_list) }}
52+
{% endif %}
53+
{% endif %}
54+
{% endif %}
55+
{% endmacro %}
56+
1557
{%- macro dremio__support_multiple_grantees_per_dcl_statement() -%}
1658
{{ return(False) }}
1759
{%- endmacro -%}

dbt/include/dremio/macros/materializations/incremental/incremental.sql

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,6 @@ limitations under the License.*/
3636
{%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}
3737
-- grab current tables grants config for comparison later on
3838
{% set grant_config = config.get('grants') %}
39-
-- ensure grant have a prefix, defaults to user if not provided
40-
{% if grant_config %}
41-
{% for privilege, grantees in grant_config.items() %}
42-
{% set updated_grantees = [] %}
43-
{% for grantee in grantees %}
44-
{% if ':' not in grantee %}
45-
{% do updated_grantees.append('user:' ~ grantee) %}
46-
{% else %}
47-
{% do updated_grantees.append(grantee) %}
48-
{% endif %}
49-
{% endfor %}
50-
{% do grant_config.update({privilege: updated_grantees}) %}
51-
{% endfor %}
52-
{% endif %}
5339
{{ drop_relation_if_exists(preexisting_intermediate_relation) }}
5440
{{ drop_relation_if_exists(preexisting_backup_relation) }}
5541

tests/functional/adapter/grants/base_grants.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import pytest
1616

17+
from dbt.context.base import BaseContext # diff_of_two_dicts only
1718
from dbt.tests.adapter.grants.base_grants import BaseGrants
1819
from tests.utils.util import BUCKET
1920

@@ -59,3 +60,12 @@ def dbt_profile_data(
5960
if profiles_config_update:
6061
profile.update(profiles_config_update)
6162
return profile
63+
64+
# Override to include assertion error message
65+
def assert_expected_grants_match_actual(self, project, relation_name, expected_grants):
66+
actual_grants = self.get_grants_on_relation(project, relation_name)
67+
# need a case-insensitive comparison
68+
# so just a simple "assert expected == actual_grants" won't work
69+
diff_a = BaseContext.diff_of_two_dicts(actual_grants, expected_grants)
70+
diff_b = BaseContext.diff_of_two_dicts(expected_grants, actual_grants)
71+
assert diff_a == diff_b == {}, f"Expected {str(expected_grants)} but got {str(actual_grants)}"

tests/functional/adapter/grants/test_seed_grants.py

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,21 @@
1414

1515
import pytest, os
1616

17-
from dbt.tests.adapter.grants.test_seed_grants import BaseSeedGrants
17+
from dbt.tests.adapter.grants.test_seed_grants import (
18+
BaseSeedGrants,
19+
user2_schema_base_yml,
20+
ignore_grants_yml,
21+
zero_grants_yml,
22+
)
1823
from tests.functional.adapter.grants.base_grants import BaseGrantsDremio
1924
from tests.utils.util import relation_from_name
20-
from dbt.tests.util import get_connection
25+
from dbt.tests.util import (
26+
get_connection,
27+
get_manifest,
28+
run_dbt,
29+
run_dbt_and_capture,
30+
write_file,
31+
)
2132

2233
DREMIO_EDITION = os.getenv("DREMIO_EDITION")
2334

@@ -38,3 +49,75 @@ def get_grants_on_relation(self, project, relation_name):
3849
_, grant_table = adapter.execute(show_grant_sql, fetch=True)
3950
actual_grants = adapter.standardize_grants_dict(grant_table)
4051
return actual_grants
52+
53+
# Override to add user prefix in expected results
54+
def test_seed_grants(self, project, get_test_users):
55+
test_users = get_test_users
56+
select_privilege_name = self.privilege_grantee_name_overrides()["select"]
57+
58+
# seed command
59+
(results, log_output) = run_dbt_and_capture(["--debug", "seed"])
60+
assert len(results) == 1
61+
manifest = get_manifest(project.project_root)
62+
seed_id = "seed.test.my_seed"
63+
seed = manifest.nodes[seed_id]
64+
expected = {select_privilege_name: ["user:" + test_users[0]]}
65+
assert "grant " in log_output
66+
self.assert_expected_grants_match_actual(project, "my_seed", expected)
67+
68+
# run it again, with no config changes
69+
(results, log_output) = run_dbt_and_capture(["--debug", "seed"])
70+
assert len(results) == 1
71+
# seeds are always full-refreshed on this adapter, so we need to re-grant
72+
assert "revoke " not in log_output
73+
assert "grant " in log_output
74+
self.assert_expected_grants_match_actual(project, "my_seed", expected)
75+
76+
# change the grantee, assert it updates
77+
updated_yaml = self.interpolate_name_overrides(user2_schema_base_yml)
78+
write_file(updated_yaml, project.project_root, "seeds", "schema.yml")
79+
(results, log_output) = run_dbt_and_capture(["--debug", "seed"])
80+
assert len(results) == 1
81+
expected = {select_privilege_name: ["user:" + test_users[1]]}
82+
self.assert_expected_grants_match_actual(project, "my_seed", expected)
83+
84+
# run it again, with --full-refresh, grants should be the same
85+
run_dbt(["seed", "--full-refresh"])
86+
self.assert_expected_grants_match_actual(project, "my_seed", expected)
87+
88+
# change config to 'grants: {}' -- should be completely ignored
89+
updated_yaml = self.interpolate_name_overrides(ignore_grants_yml)
90+
write_file(updated_yaml, project.project_root, "seeds", "schema.yml")
91+
(results, log_output) = run_dbt_and_capture(["--debug", "seed"])
92+
assert len(results) == 1
93+
assert "revoke " not in log_output
94+
assert "grant " not in log_output
95+
manifest = get_manifest(project.project_root)
96+
seed_id = "seed.test.my_seed"
97+
seed = manifest.nodes[seed_id]
98+
expected_config = {}
99+
expected_actual = {select_privilege_name: [test_users[1]]}
100+
if self.seeds_support_partial_refresh():
101+
# ACTUAL grants will NOT match expected grants
102+
self.assert_expected_grants_match_actual(project, "my_seed", expected_actual)
103+
else:
104+
# there should be ZERO grants on the seed
105+
self.assert_expected_grants_match_actual(project, "my_seed", expected_config)
106+
107+
# now run with ZERO grants -- all grants should be removed
108+
# whether explicitly (revoke) or implicitly (recreated without any grants added on)
109+
updated_yaml = self.interpolate_name_overrides(zero_grants_yml)
110+
write_file(updated_yaml, project.project_root, "seeds", "schema.yml")
111+
(results, log_output) = run_dbt_and_capture(["--debug", "seed"])
112+
assert len(results) == 1
113+
if self.seeds_support_partial_refresh():
114+
assert "revoke " in log_output
115+
expected = {}
116+
self.assert_expected_grants_match_actual(project, "my_seed", expected)
117+
118+
# run it again -- dbt shouldn't try to grant or revoke anything
119+
(results, log_output) = run_dbt_and_capture(["--debug", "seed"])
120+
assert len(results) == 1
121+
assert "revoke " not in log_output
122+
assert "grant " not in log_output
123+
self.assert_expected_grants_match_actual(project, "my_seed", expected)

0 commit comments

Comments
 (0)