Skip to content

Commit

Permalink
Support for roles in grants (#259)
Browse files Browse the repository at this point in the history
### Summary

Added support for roles in grants

### Description

Grants can now be set for both users and for roles.
A prefix was added to handle this, with `user:` and `role:` being the
valid prefixes. For example, `user:dbt_test_user_1` and
`role:dbt_test_role_1`.
If no prefix is provided, defaults to user for backwards compatibility.

### Test Results

Tests were ran against a local Dremio Enterprise instance and are
skipped since the current pipeline uses Dremio OSS, and grants are an
Enterprise feature

### Changelog

- Added support for roles in grants

### Related Issue

#177
  • Loading branch information
bcmeireles authored Jan 27, 2025
1 parent d2ca686 commit 0e9c546
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 21 deletions.
6 changes: 0 additions & 6 deletions .github/expected_failures.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ tests/functional/adapter/dbt_clone/test_dbt_clone.py::TestCloneNotPossibleDremio
tests/functional/adapter/dremio_specific/test_drop_temp_table.py::TestDropTempTableDremio::test_drop_temp_table
tests/functional/adapter/dremio_specific/test_schema_parsing.py::TestSchemaParsingDremio::test_schema_with_dots
tests/functional/adapter/dremio_specific/test_verify_ssl.py::TestVerifyCertificateDremio::test_insecure_request_warning_not_exist
tests/functional/adapter/grants/test_incremental_grants.py::TestIncrementalGrantsDremio::test_incremental_grants
tests/functional/adapter/grants/test_invalid_grants.py::TestInvalidGrantsDremio::test_invalid_grants
tests/functional/adapter/grants/test_model_grants.py::TestViewGrantsDremio::test_view_table_grants
tests/functional/adapter/grants/test_model_grants.py::TestTableGrantsDremio::test_view_table_grants
tests/functional/adapter/grants/test_seed_grants.py::TestSeedGrantsDremio::test_seed_grants
tests/functional/adapter/grants/test_snapshot_grants.py::TestSnapshotGrantsDremio::test_snapshot_grants
tests/functional/adapter/relation/test_get_relation_last_modified.py::TestGetLastRelationModified::test_get_last_relation_modified
tests/functional/adapter/unit_testing/test_unit_testing.py::TestDremioUnitTestingTypes::test_unit_test_data_type
tests/functional/adapter/unit_testing/test_unit_testing.py::TestDremioUnitTestCaseInsensitivity::test_case_insensitivity
Expand Down
3 changes: 3 additions & 0 deletions .github/scripts/create_env_file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ DREMIO_DATABASE=dbt_test
DBT_TEST_USER_1=dbt_test_user_1
DBT_TEST_USER_2=dbt_test_user_2
DBT_TEST_USER_3=dbt_test_user_3
DBT_TEST_ROLE_1=dbt_test_role_1
DBT_TEST_ROLE_2=dbt_test_role_2
DREMIO_EDITION=community
EOF

echo ".env file created successfully."
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
## Changes

- When naming reflections, if a `name` config is not set, the `alias` config parameter will be used instead. If also undefined, it will refer to the model name instead of using `Unnamed Reflection`
- Grants can now be set for both users and for roles. A prefix was added to handle this, with `user:` and `role:` being the valid prefixes. For example, `user:dbt_test_user_1` and `role:dbt_test_role_1`. If no prefix is provided, defaults to user for backwards compatibility.

## Features

- [#259](https://github.com/dremio/dbt-dremio/pull/259) Added support for roles in grants

# dbt-dremio v1.8.1

Expand Down
6 changes: 4 additions & 2 deletions dbt/adapters/dremio/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,12 @@ def standardize_grants_dict(self, grants_table: agate.Table) -> dict:
# Just needed to change these two values to match Dremio cols
grantee = row["grantee_id"]
privilege = row["privilege"]
grantee_type = row["grantee_type"]

if privilege in grants_dict.keys():
grants_dict[privilege].append(grantee)
grants_dict[privilege].append(f"{grantee_type}:{grantee}")
else:
grants_dict.update({privilege: [grantee]})
grants_dict.update({privilege: [f"{grantee_type}:{grantee}"]})
return grants_dict

# This is for use in the test suite
Expand Down
32 changes: 28 additions & 4 deletions dbt/include/dremio/macros/adapters/apply_grants.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@ limitations under the License.*/
{{ return(False) }}
{%- endmacro -%}

{%- macro dremio__split_grantee(grantee) -%}
{%- set splitted = grantee.split(':') -%}

{%- if splitted | length < 2 -%}
{{ log("Deprecation warning: grants to users will soon require the user: prefix", info=True) }}
{{ return(("user", grantee)) }}
{%- else -%}
{%- set prefix = splitted[0] -%}
{%- set remainder = splitted[1:] | join(':') -%}

{%- if prefix not in ['user', 'role'] -%}
{% do exceptions.CompilationError("Invalid prefix. Use either user or role") %}
{%- endif -%}

{{ return((prefix, remainder)) }}
{%- endif -%}
{%- endmacro -%}

{% macro dremio__get_show_grant_sql(relation) %}
{%- if relation.type == 'table' -%}
{%- set relation_without_double_quotes = target.datalake ~ '.' ~ target.root_path ~ '.' ~ relation.identifier-%}
Expand All @@ -30,17 +48,23 @@ limitations under the License.*/
{%- else -%}
{% do exceptions.CompilationError("Invalid profile configuration: please only specify one of cloud_host or software_host in profiles.yml") %}
{%- endif %}
SELECT privilege, grantee_id
SELECT privilege, grantee_type, grantee_id
FROM {{privileges_table}}
WHERE object_id='{{ relation_without_double_quotes }}'
{% endmacro %}

{%- macro dremio__get_grant_sql(relation, privilege, grantees) -%}
grant {{ privilege }} on {{relation.type}} {{ relation }} to user {{adapter.quote(grantees[0])}}
{%- set type, name = dremio__split_grantee(grantees[0]) %}

grant {{ privilege }} on {{ relation.type }} {{ relation }}
to {{ type }} {{ adapter.quote(name) }}
{%- endmacro -%}

{%- macro default__get_revoke_sql(relation, privilege, grantees) -%}
revoke {{ privilege }} on {{ relation.type }} {{ relation }} from user {{adapter.quote(grantees[0])}}
{%- macro dremio__get_revoke_sql(relation, privilege, grantees) -%}
{%- set type, name = dremio__split_grantee(grantees[0]) %}

revoke {{ privilege }} on {{ relation.type }} {{ relation }}
from {{ type }} {{ adapter.quote(name) }}
{%- endmacro -%}

{% macro dremio__call_dcl_statements(dcl_statement_list) %}
Expand Down
8 changes: 6 additions & 2 deletions tests/functional/adapter/grants/test_incremental_grants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest, os

from dbt.tests.util import (
run_dbt_and_capture,
get_manifest,
Expand All @@ -26,7 +28,9 @@
user2_incremental_model_schema_yml,
)

DREMIO_EDITION = os.getenv("DREMIO_EDITION")

@pytest.mark.skipif(DREMIO_EDITION == "community", reason="Dremio only supports grants in EE/DC editions.")
class TestIncrementalGrantsDremio(BaseGrantsDremio, BaseIncrementalGrants):
# Define this here to use our modified version of relation_from_name
def get_grants_on_relation(self, project, relation_name):
Expand All @@ -53,7 +57,7 @@ def test_incremental_grants(self, project, get_test_users):
model_id = "model.test.my_incremental_model"
model = manifest.nodes[model_id]
assert model.config.materialized == "incremental"
expected = {select_privilege_name: [test_users[0]]}
expected = {select_privilege_name: ["user:" + test_users[0]]}
self.assert_expected_grants_match_actual(
project, "my_incremental_model", expected
)
Expand All @@ -80,7 +84,7 @@ def test_incremental_grants(self, project, get_test_users):
manifest = get_manifest(project.project_root)
model = manifest.nodes[model_id]
assert model.config.materialized == "incremental"
expected = {select_privilege_name: [test_users[1]]}
expected = {select_privilege_name: ["user:" + test_users[1]]}
self.assert_expected_grants_match_actual(
project, "my_incremental_model", expected
)
Expand Down
3 changes: 3 additions & 0 deletions tests/functional/adapter/grants/test_invalid_grants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest, os

from dbt.tests.adapter.grants.test_invalid_grants import BaseInvalidGrants
from tests.functional.adapter.grants.base_grants import BaseGrantsDremio
from tests.utils.util import relation_from_name
from dbt.tests.util import get_connection

DREMIO_EDITION = os.getenv("DREMIO_EDITION")

@pytest.mark.skipif(DREMIO_EDITION == "community", reason="Dremio only supports grants in EE/DC editions.")
class TestInvalidGrantsDremio(BaseGrantsDremio, BaseInvalidGrants):
def grantee_does_not_exist_error(self):
return "Grant on catalog entity failed. User invalid_user does not exist."
Expand Down
Loading

0 comments on commit 0e9c546

Please sign in to comment.