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

Copy grants while deploying snowpark functions and procedures #1185

Merged
merged 2 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
## Fixes and improvements
* Fixed error handling for malformatted `config.toml`
* Fixed ZIP packaging of Snowpark project dependencies containing implicit namespace packages like `snowflake`.
* Deploying function/procedure with `--replace` flag now copies all grants

# v2.4.0
## Backward incompatibility
Expand Down
1 change: 1 addition & 0 deletions src/snowflake/cli/plugins/snowpark/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def create_query(

query = [
f"create or replace {self._object_type.value.sf_name} {identifier}",
f"copy grants",
f"returns {return_type}",
"language python",
f"runtime_version={runtime or DEFAULT_RUNTIME}",
Expand Down
4 changes: 4 additions & 0 deletions tests/snowpark/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def test_deploy_function(
dedent(
"""\
create or replace function MockDatabase.MockSchema.func1(a string default 'default value', b variant)
copy grants
returns string
language python
runtime_version=3.10
Expand Down Expand Up @@ -85,6 +86,7 @@ def test_deploy_function_with_external_access(
dedent(
"""\
create or replace function MockDatabase.MockSchema.func1(a string, b variant)
copy grants
returns string
language python
runtime_version=3.8
Expand Down Expand Up @@ -204,6 +206,7 @@ def test_deploy_function_needs_update_because_packages_changes(
dedent(
"""\
create or replace function MockDatabase.MockSchema.func1(a string default 'default value', b variant)
copy grants
returns string
language python
runtime_version=3.10
Expand Down Expand Up @@ -254,6 +257,7 @@ def test_deploy_function_needs_update_because_handler_changes(
dedent(
"""\
create or replace function MockDatabase.MockSchema.func1(a string default 'default value', b variant)
copy grants
returns string
language python
runtime_version=3.10
Expand Down
3 changes: 3 additions & 0 deletions tests/snowpark/test_procedure.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def test_deploy_procedure(
dedent(
"""\
create or replace procedure MockDatabase.MockSchema.procedureName(name string)
copy grants
returns string
language python
runtime_version=3.8
Expand All @@ -69,6 +70,7 @@ def test_deploy_procedure(
dedent(
"""\
create or replace procedure MockDatabase.MockSchema.test()
copy grants
returns string
language python
runtime_version=3.10
Expand Down Expand Up @@ -124,6 +126,7 @@ def test_deploy_procedure_with_external_access(
dedent(
"""\
create or replace procedure MockDatabase.MockSchema.procedureName(name string)
copy grants
returns string
language python
runtime_version=3.8
Expand Down
46 changes: 46 additions & 0 deletions tests_integration/test_snowpark.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,36 @@ def test_snowpark_flow(
returns="VARCHAR(16777216)",
)

# Grants are given correctly

_test_steps.set_grants_on_selected_object(
object_type="procedure",
object_name="hello_procedure(VARCHAR)",
privillege="USAGE",
role="test_role",
)

_test_steps.set_grants_on_selected_object(
object_type="function",
object_name="hello_function(VARCHAR)",
privillege="USAGE",
role="test_role",
)

_test_steps.assert_that_object_has_expected_grant(
object_type="procedure",
object_name="hello_procedure(VARCHAR)",
expected_privillege="USAGE",
expected_role="test_role",
)

_test_steps.assert_that_object_has_expected_grant(
object_type="function",
object_name="hello_function(VARCHAR)",
expected_privillege="USAGE",
expected_role="test_role",
)

# Created objects can be executed
_test_steps.snowpark_execute_should_return_expected_value(
object_type="procedure",
Expand Down Expand Up @@ -215,6 +245,22 @@ def test_snowpark_flow(
*expected_files, stage_name=STAGE_NAME
)

# Grants are preserved after updates

_test_steps.assert_that_object_has_expected_grant(
object_type="procedure",
object_name="hello_procedure(VARCHAR)",
expected_privillege="USAGE",
expected_role="test_role",
)

_test_steps.assert_that_object_has_expected_grant(
object_type="function",
object_name="hello_function(VARCHAR)",
expected_privillege="USAGE",
expected_role="test_role",
)

# Check if objects can be dropped
_test_steps.object_drop_should_finish_successfully(
object_type="procedure", identifier="hello_procedure(varchar)"
Expand Down
27 changes: 27 additions & 0 deletions tests_integration/testing_utils/snowpark_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,30 @@ def get_actual_files_staged_in_db(self, stage_name: str):
stage_name=stage_name
)
]

def set_grants_on_selected_object(
self, object_type: str, object_name: str, privillege: str, role: str
):
self._setup.sql_test_helper.execute_single_sql(
f"GRANT {privillege} ON {object_type} {object_name} TO ROLE {role};"
)

def assert_that_object_has_expected_grant(
self,
object_type: str,
object_name: str,
expected_privillege: str,
expected_role: str,
):
result = self._setup.sql_test_helper.execute_single_sql(
f"SHOW GRANTS ON {object_type} {object_name};"
)
assert any(
[
(
grant.get("privilege") == expected_privillege.upper()
and grant.get("grantee_name") == expected_role.upper()
)
for grant in result
]
)
Loading