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)

Reply via email to