This is an automated email from the ASF dual-hosted git repository. ephraimanierobi pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push: new 7b3a5f9 Hide variable import form if user lacks permission (#18000) 7b3a5f9 is described below commit 7b3a5f95cd19667a683e92e311f6c29d6a9a6a0b Author: Jed Cunningham <66968678+jedcunning...@users.noreply.github.com> AuthorDate: Fri Sep 3 01:34:51 2021 -0600 Hide variable import form if user lacks permission (#18000) This hides the variable import form if the user does not have the "can create on variable" permission. --- airflow/www/templates/airflow/variable_list.html | 2 ++ airflow/www/views.py | 6 ++++ tests/www/views/test_views_variable.py | 35 +++++++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/airflow/www/templates/airflow/variable_list.html b/airflow/www/templates/airflow/variable_list.html index 0e41a87..a9d58b2 100644 --- a/airflow/www/templates/airflow/variable_list.html +++ b/airflow/www/templates/airflow/variable_list.html @@ -20,6 +20,7 @@ {% extends 'appbuilder/general/model/list.html' %} {% block content %} + {% if can_create_variable() %} <div class="well well-sm pull-left"> <form class="form-inline" action="{{ url_for('VariableModelView.varimport') }}" method="post" enctype="multipart/form-data"> {% if csrf_token %} @@ -35,5 +36,6 @@ </form> </div> <div class="clearfix"></div> + {% endif %} {{ super() }} {% endblock %} diff --git a/airflow/www/views.py b/airflow/www/views.py index d5428b3..33720e7 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -3570,6 +3570,10 @@ class PoolModelView(AirflowModelView): validators_columns = {'pool': [validators.DataRequired()], 'slots': [validators.NumberRange(min=-1)]} +def _can_create_variable() -> bool: + return current_app.appbuilder.sm.has_access(permissions.ACTION_CAN_CREATE, permissions.RESOURCE_VARIABLE) + + class VariableModelView(AirflowModelView): """View to show records from Variable table""" @@ -3625,6 +3629,8 @@ class VariableModelView(AirflowModelView): if secrets_masker.should_hide_value_for_key(form.key.data): form.val.data = '*' * 8 + extra_args = {"can_create_variable": _can_create_variable} + @action('muldelete', 'Delete', 'Are you sure you want to delete selected records?', single=False) def action_muldelete(self, items): """Multiple delete.""" diff --git a/tests/www/views/test_views_variable.py b/tests/www/views/test_views_variable.py index 65d6a27..8da4090 100644 --- a/tests/www/views/test_views_variable.py +++ b/tests/www/views/test_views_variable.py @@ -21,8 +21,10 @@ from unittest import mock import pytest from airflow.models import Variable +from airflow.security import permissions from airflow.utils.session import create_session -from tests.test_utils.www import check_content_in_response, check_content_not_in_response +from tests.test_utils.api_connexion_utils import create_user +from tests.test_utils.www import check_content_in_response, check_content_not_in_response, client_with_login VARIABLE = { 'key': 'test_key', @@ -38,6 +40,27 @@ def clear_variables(): session.query(Variable).delete() +@pytest.fixture(scope="module") +def user_variable_reader(app): + """Create User that can only read variables""" + return create_user( + app, + username="user_variable_reader", + role_name="role_variable_reader", + permissions=[(permissions.ACTION_CAN_READ, permissions.RESOURCE_VARIABLE)], + ) + + +@pytest.fixture() +def client_variable_reader(app, user_variable_reader): + """Client for User that can only access the first DAG from TEST_FILTER_DAG_IDS""" + return client_with_login( + app, + username="user_variable_reader", + password="user_variable_reader", + ) + + def test_can_handle_error_on_decrypt(session, admin_client): # create valid variable admin_client.post('/variable/add', data=VARIABLE, follow_redirects=True) @@ -109,6 +132,16 @@ def test_import_variables_anon(session, app): check_content_in_response('Sign In', resp) +def test_import_variables_form_shown(app, admin_client): + resp = admin_client.get('/variable/list/') + check_content_in_response('Import Variables', resp) + + +def test_import_variables_form_hidden(app, client_variable_reader): + resp = client_variable_reader.get('/variable/list/') + check_content_not_in_response('Import Variables', resp) + + def test_description_retrieval(session, admin_client): # create valid variable admin_client.post('/variable/add', data=VARIABLE, follow_redirects=True)