diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 99d580d41e..1cd56d25a0 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -22,6 +22,7 @@ ## Fixes and improvements * Bumped `snowflake-connector-python==3.17.4` +* Grant privileges defined in `snowflake.yml` after deploying Streamlit # v3.12.0 diff --git a/src/snowflake/cli/_plugins/streamlit/streamlit_entity.py b/src/snowflake/cli/_plugins/streamlit/streamlit_entity.py index b653892f2e..3054fec239 100644 --- a/src/snowflake/cli/_plugins/streamlit/streamlit_entity.py +++ b/src/snowflake/cli/_plugins/streamlit/streamlit_entity.py @@ -6,6 +6,7 @@ from snowflake.cli._plugins.connection.util import make_snowsight_url from snowflake.cli._plugins.nativeapp.artifacts import build_bundle from snowflake.cli._plugins.stage.manager import StageManager +from snowflake.cli._plugins.streamlit.manager import StreamlitManager from snowflake.cli._plugins.streamlit.streamlit_entity_model import ( StreamlitEntityModel, ) @@ -132,6 +133,8 @@ def deploy( self.get_deploy_sql(replace=replace, from_stage_name=stage_root) ) + StreamlitManager(connection=self._conn).grant_privileges(self.model) + return self.perform(EntityActions.GET_URL, action_context, *args, **kwargs) def describe(self) -> SnowflakeCursor: @@ -256,3 +259,5 @@ def _deploy_experimental( print_diff=True, force_overwrite=True, # files copied to streamlit vstage need to be overwritten ) + + StreamlitManager(connection=self._conn).grant_privileges(self.model) diff --git a/tests_integration/test_streamlit.py b/tests_integration/test_streamlit.py index 086444d3f0..32b43e0135 100644 --- a/tests_integration/test_streamlit.py +++ b/tests_integration/test_streamlit.py @@ -132,3 +132,57 @@ def _test_setup( @pytest.fixture def _streamlit_test_steps(_test_setup): return StreamlitTestSteps(_test_setup) + + +@pytest.mark.integration +def test_streamlit_grants_flow( + _streamlit_test_steps, + project_directory, + snowflake_session, + alter_snowflake_yml, +): + """Test that streamlit grants are properly applied during deployment.""" + test_role = snowflake_session.role + entity_id = "app_1" + + with project_directory("streamlit_v2"): + alter_snowflake_yml( + "snowflake.yml", + "entities.app_1.grants", + [{"privilege": "USAGE", "role": test_role}], + ) + + _streamlit_test_steps.deploy_with_entity_id_specified_should_succeed( + entity_id, snowflake_session, experimental=False + ) + + _streamlit_test_steps.verify_grants_applied(entity_id, test_role) + + _streamlit_test_steps.drop_should_succeed(entity_id, snowflake_session) + + +@pytest.mark.integration +def test_streamlit_grants_experimental_flow( + _streamlit_test_steps, + project_directory, + snowflake_session, + alter_snowflake_yml, +): + """Test that streamlit grants are properly applied during experimental deployment.""" + test_role = snowflake_session.role + entity_id = "app_1" + + with project_directory("streamlit_v2"): + alter_snowflake_yml( + "snowflake.yml", + "entities.app_1.grants", + [{"privilege": "USAGE", "role": test_role}], + ) + + _streamlit_test_steps.deploy_with_entity_id_specified_should_succeed( + entity_id, snowflake_session, experimental=True + ) + + _streamlit_test_steps.verify_grants_applied(entity_id, test_role) + + _streamlit_test_steps.drop_should_succeed(entity_id, snowflake_session) diff --git a/tests_integration/testing_utils/streamlit_utils.py b/tests_integration/testing_utils/streamlit_utils.py index 618f5a430f..1704a5bfd4 100644 --- a/tests_integration/testing_utils/streamlit_utils.py +++ b/tests_integration/testing_utils/streamlit_utils.py @@ -183,6 +183,15 @@ def assert_proper_url_is_returned( assert message.startswith("Streamlit successfully deployed and available under") assert message.endswith(create_expected_url_suffix(entity_id, session)) + def verify_grants_applied(self, entity_id: str, test_role: str): + self.setup.sql_test_helper.execute_single_sql(f"USE ROLE {test_role}") + streamlits_with_role = self.setup.sql_test_helper.execute_single_sql( + f"SHOW STREAMLITS LIKE '{entity_id}'" + ) + assert ( + len(streamlits_with_role) == 1 + ), f"Role {test_role} should have USAGE access to the streamlit" + def create_expected_url_suffix(entity_id: str, session: SnowflakeConnection): return f".snowflake.com/SFENGINEERING/{get_account(session)}/#/streamlit-apps/{session.database.upper()}.{session.schema.upper()}.{entity_id.upper()}"