Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CT-808 more grant adapter tests #5452

Merged
merged 18 commits into from
Jul 11, 2022

Conversation

gshank
Copy link
Contributor

@gshank gshank commented Jul 8, 2022

resolves #5447

Description

More adapter tests

Checklist

@gshank gshank added the Skip Changelog Skips GHA to check for changelog file label Jul 8, 2022
@gshank gshank requested a review from a team as a code owner July 8, 2022 02:32
@gshank gshank requested review from emmyoop and McKnight-42 July 8, 2022 02:32
@cla-bot cla-bot bot added the cla:yes label Jul 8, 2022
@gshank
Copy link
Contributor Author

gshank commented Jul 8, 2022

I roughed in some tests but mostly they just verify that things don't die. Didn't have time to do more specific grant checks, but wanted to get things going for someone else to work on.

@gshank gshank requested a review from jtcohen6 July 8, 2022 02:34
@McKnight-42
Copy link
Contributor

Thank you Gerda this looks great!

@gshank gshank requested a review from a team July 8, 2022 12:57
@gshank gshank requested a review from a team as a code owner July 8, 2022 12:57
@gshank gshank requested a review from ChenyuLInx July 8, 2022 12:57
self.assert_expected_grants_match_actual(project, "my_snapshot", expected)

# run it again, nothing should have changed
(results, log_output) = run_dbt_and_capture(["snapshot"])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you might need to use "--debug" for the log lines that would normally contain the select and revoke statements to have a chance to actually be in the log.

self.assert_expected_grants_match_actual(project, "my_seed", expected)

# run it again, nothing should have changed
(results, log_output) = run_dbt_and_capture(["seed"])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we need to use "--debug" here to capture the right log output?

assert len(test_users) == 3

# Incremental materialization, single select grant
write_file(incremental_model_schema_yml, project.project_root, "models", "schema.yml")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This line isn't needed, since the "models" fixture will write the file out and it hasn't changed.


def test_nonexistent_grantee(self, project, get_test_users, logs_dir):
# failure when grant to a user/role that doesn't exist
write_file(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Line isn't needed since file has been written out from models fixture.

@gshank gshank requested a review from a team as a code owner July 8, 2022 20:58
core/dbt/context/base.py Outdated Show resolved Hide resolved
Copy link
Contributor

@ChenyuLInx ChenyuLInx left a comment

Choose a reason for hiding this comment

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

Looks great over all, have some minor questions

core/dbt/context/base.py Outdated Show resolved Hide resolved
@@ -34,54 +34,76 @@
{% endmacro %}

{%- macro default__get_grant_sql(relation, grant_config) -%}
{%- for privilege in grant_config.keys() -%}
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't have to adjust in this PR, but have we considered move all these kind of logic to python vs do them in Jinja

Copy link
Contributor

@jtcohen6 jtcohen6 Jul 9, 2022

Choose a reason for hiding this comment

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

I was thinking about this yesterday. Both get_grant_sql and get_revoke_sql now have the same boilerplate, which is unpacking the grant config and looping over them. The piece of this that really wants to be in Jinja is really more like:

{% macro get_grant_sql() %}
    grant {{ privilege }} on {{ relation }} to {{ grantee }}
{% endmacro %}

I could see refactoring to call this simpler macro instead, and move the unpacking/looping/array-building logic elsewhere.

For what it's worth, most of the heavier lifting is really happening in apply_grants. We could reimplemented some pieces of it in Python. Keeping the top-level macro call in Jinja (=user space) does allow people to override its behavior for themselves, though.

Copy link
Contributor

Choose a reason for hiding this comment

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

I acted on this feedback in c763601, by moving the grant_config unpacking / looping logic into their own separate reusable macro, so that get_grant_sql + get_revoke_sql can be dead simple

Copy link
Contributor

Choose a reason for hiding this comment

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

@jtcohen6 solid move! I also like @ChenyuLInx's notion of putting more looping logic into Python to make the Jinja simpler.

Copy link
Contributor

Choose a reason for hiding this comment

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

Totally. It can be fairly tricky today to call macros from within Python models (adapter.execute_macro is the sort-of state-of-art), so when a macro needs to call other macros (as this one does), Jinja can still be easier. But if we can split out a pure function, as we did with diff_of_two_dicts and standardize_grants_dict, Python is wayyyy better for code clarity and to unit testing.

Copy link
Contributor

@dbeatty10 dbeatty10 left a comment

Choose a reason for hiding this comment

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

👍
This modularization turned out nicely!

@dataders note that this PR introduces several bits of functionality that can be overridden by adapters.

Comment on lines +676 to +682
dict_b_lowered = {k.casefold(): [x.casefold() for x in v] for k, v in dict_b.items()}
for k in dict_a:
if k in dict_b:
a_lowered = map(lambda x: x.lower(), dict_a[k])
b_lowered = map(lambda x: x.lower(), dict_b[k])
diff = list(set(a_lowered) - set(b_lowered))
if k.casefold() in dict_b_lowered.keys():
diff = []
for v in dict_a[k]:
if v.casefold() not in dict_b_lowered[k.casefold()]:
diff.append(v)
Copy link
Contributor

Choose a reason for hiding this comment

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

casefold, FTW 💪

Copy link
Contributor

Choose a reason for hiding this comment

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

oh wow thats super cool haven't heard of casefold before.

Copy link
Contributor

Choose a reason for hiding this comment

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

@nathaniel-may is going to take a look at refactoring this for performance / Pythonic-ness. Not going to consider it a blocker for merging this PR in the meantime.

Comment on lines 45 to 51
# Adapters will need to reimplement these methods with the specific
# language of their database
def grantee_does_not_exist_error(self):
return "does not exist"

def privilege_does_not_exist_error(self):
return "unrecognized privilege"
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

can we add a doc string here to say what they're supposed to do? or examples? I'm happy to do this, but i"m not sure of their functionality right now..

Copy link
Contributor

@jtcohen6 jtcohen6 Jul 11, 2022

Choose a reason for hiding this comment

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

Yup, there's a comment to this effect above:

# The purpose of this test is to understand the user experience when providing
# an invalid 'grants' configuration. dbt will *not* try to intercept or interpret
# the database's own error at runtime -- it will just return those error messages.
# Hopefully they're helpful!

Is this a useful test? It's checking for specific language in the DatabaseError that dbt will be passing back. That may be annoying, as an adapter maintainer: this test is basically guaranteed to fail, until/unless you reimplement grantee_does_not_exist_error + privilege_does_not_exist_error with language from your own database's error message. But I do like that, as dbt maintainers, we're thinking harder about the UX for these common error cases than we have in the past. "dbt is just returning the error from the database" is only as useful as the actual error from the actual database. We do call them "the thorniest errors of all" for good reason.

@@ -13,7 +13,7 @@
check_cols='all', unique_key='id', strategy='check',
target_database=database, target_schema=schema
) }}
select 1 as id, 'blue' as color
select 1 as id, cast('blue' as {{ type_string() }}) as color
Copy link
Contributor

Choose a reason for hiding this comment

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

💚 from the Redshift adapter

Copy link
Contributor

@McKnight-42 McKnight-42 left a comment

Choose a reason for hiding this comment

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

This is all looking fantastic! LGTM

@McKnight-42 McKnight-42 merged commit 794f4d1 into ct-660-grant-sql Jul 11, 2022
@McKnight-42 McKnight-42 deleted the ct-808-more_grant_adapter_tests branch July 11, 2022 15:06
McKnight-42 added a commit that referenced this pull request Jul 11, 2022
* init push or ct-660 work

* changes to default versions of get_show_grant_sql and get_grant_sql

* completing init default versions of all macros being called for look over and collaboration

* minor update to should_revoke

* post pairing push up (does have log statements to make sure we remove)

* minor spacing changes

* minor changes, and removal of logs so people can have clean grab of code

* minor changes to how get_revoke_sql works

* init attempt at applying apply_grants to all materialzations

* name change from recipents -> grantee

* minor changes

* working on making a context to handle the diff gathering between grant_config and curreent_grants to see what needs to be revoked, I know if we assign a role, and a model becomes dependent on it we can't drop the role now still not seeing the diff appear in log

* removing logs from most materializations to better track diff of grants generation logs

* starting to build out postgres get_show_grant_sql getting empty query errors hopefully will clear up as we add the other postgres versions of macros and isn't a psycopg2 issue as indicated by searching

* 6/27 eod update looking into diff_grants variable not getting passed into get_revoke_sql

* changes to loop cases

* changes after pairing meeting

* adding apply_grants to create_or_replace_view.sql

* models are building but testing out small issues around revoke statement never building

* postgrest must fixes from jeremy's feedback

* postgres minor change to standarize_grants_dict

* updating after pairing with dough and jeremey incorporating the new version of should revoke logic.

* adding  ref of diff_of_two_dicts to base keys ref

* change of method type for standardize_grants_dict

* minor update trying to fix unit test

* changes based on morning feedback

* change log message in default_apply_grants macro

* CT-808 grant adapter tests (#5447)

* Create initial test for grants

Co-authored-by: Jeremy Cohen <jeremy@dbtlabs.com>

* rename grant[privilege] -> grant_config[privilege]

* postgres macro rename to copy_grants

* CT-808 more grant adapter tests (#5452)

* Add tests for invalid user and invalid privilege

* Add more grant tests

* Macro touch ups

* Many more tests

* Allow easily replacing privilege names

* Keep adding tests

* Refactor macros to return lists, fix test

* Code checks

* Keep tweaking tests

* Revert cool grantees join bc Snowflake isnt happy

* Use Postgres/BQ as standard for standardize_grants_dict

* Code checks

* add missing replace

* small replace tweak,  add additional dict diffs

* All tests passing on BQ

* Add type cast to test_snapshot_grants

* Refactor for DRYer apply_grants macros

Co-authored-by: Jeremy Cohen <jeremy@dbtlabs.com>
Co-authored-by: Emily Rockman <emily.rockman@dbtlabs.com>

* update to main, create changelog, whitespace fixes

Co-authored-by: Gerda Shank <gerda@dbtlabs.com>
Co-authored-by: Jeremy Cohen <jeremy@dbtlabs.com>
Co-authored-by: Emily Rockman <emily.rockman@dbtlabs.com>
agoblet pushed a commit to BigDataRepublic/dbt-core that referenced this pull request Sep 16, 2022
* init push or ct-660 work

* changes to default versions of get_show_grant_sql and get_grant_sql

* completing init default versions of all macros being called for look over and collaboration

* minor update to should_revoke

* post pairing push up (does have log statements to make sure we remove)

* minor spacing changes

* minor changes, and removal of logs so people can have clean grab of code

* minor changes to how get_revoke_sql works

* init attempt at applying apply_grants to all materialzations

* name change from recipents -> grantee

* minor changes

* working on making a context to handle the diff gathering between grant_config and curreent_grants to see what needs to be revoked, I know if we assign a role, and a model becomes dependent on it we can't drop the role now still not seeing the diff appear in log

* removing logs from most materializations to better track diff of grants generation logs

* starting to build out postgres get_show_grant_sql getting empty query errors hopefully will clear up as we add the other postgres versions of macros and isn't a psycopg2 issue as indicated by searching

* 6/27 eod update looking into diff_grants variable not getting passed into get_revoke_sql

* changes to loop cases

* changes after pairing meeting

* adding apply_grants to create_or_replace_view.sql

* models are building but testing out small issues around revoke statement never building

* postgrest must fixes from jeremy's feedback

* postgres minor change to standarize_grants_dict

* updating after pairing with dough and jeremey incorporating the new version of should revoke logic.

* adding  ref of diff_of_two_dicts to base keys ref

* change of method type for standardize_grants_dict

* minor update trying to fix unit test

* changes based on morning feedback

* change log message in default_apply_grants macro

* CT-808 grant adapter tests (dbt-labs#5447)

* Create initial test for grants

Co-authored-by: Jeremy Cohen <jeremy@dbtlabs.com>

* rename grant[privilege] -> grant_config[privilege]

* postgres macro rename to copy_grants

* CT-808 more grant adapter tests (dbt-labs#5452)

* Add tests for invalid user and invalid privilege

* Add more grant tests

* Macro touch ups

* Many more tests

* Allow easily replacing privilege names

* Keep adding tests

* Refactor macros to return lists, fix test

* Code checks

* Keep tweaking tests

* Revert cool grantees join bc Snowflake isnt happy

* Use Postgres/BQ as standard for standardize_grants_dict

* Code checks

* add missing replace

* small replace tweak,  add additional dict diffs

* All tests passing on BQ

* Add type cast to test_snapshot_grants

* Refactor for DRYer apply_grants macros

Co-authored-by: Jeremy Cohen <jeremy@dbtlabs.com>
Co-authored-by: Emily Rockman <emily.rockman@dbtlabs.com>

* update to main, create changelog, whitespace fixes

Co-authored-by: Gerda Shank <gerda@dbtlabs.com>
Co-authored-by: Jeremy Cohen <jeremy@dbtlabs.com>
Co-authored-by: Emily Rockman <emily.rockman@dbtlabs.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla:yes Skip Changelog Skips GHA to check for changelog file
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants