cornflow 1.2.3a2__py3-none-any.whl → 1.2.3a4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cornflow/app.py +1 -1
- cornflow/cli/roles.py +1 -1
- cornflow/cli/service.py +32 -4
- cornflow/commands/access.py +14 -3
- cornflow/commands/auxiliar.py +100 -0
- cornflow/commands/permissions.py +164 -100
- cornflow/commands/roles.py +15 -14
- cornflow/commands/views.py +171 -41
- cornflow/shared/authentication/auth.py +3 -3
- cornflow/shared/const.py +1 -1
- cornflow/tests/unit/test_commands.py +0 -147
- cornflow/tests/unit/test_external_role_creation.py +539 -0
- {cornflow-1.2.3a2.dist-info → cornflow-1.2.3a4.dist-info}/METADATA +2 -2
- {cornflow-1.2.3a2.dist-info → cornflow-1.2.3a4.dist-info}/RECORD +17 -15
- {cornflow-1.2.3a2.dist-info → cornflow-1.2.3a4.dist-info}/WHEEL +0 -0
- {cornflow-1.2.3a2.dist-info → cornflow-1.2.3a4.dist-info}/entry_points.txt +0 -0
- {cornflow-1.2.3a2.dist-info → cornflow-1.2.3a4.dist-info}/top_level.txt +0 -0
cornflow/app.py
CHANGED
@@ -164,7 +164,7 @@ def create_base_user(username, email, password, verbose):
|
|
164
164
|
@click.option("-v", "--verbose", is_flag=True, default=False)
|
165
165
|
@with_appcontext
|
166
166
|
def register_roles(verbose):
|
167
|
-
register_roles_command(verbose)
|
167
|
+
register_roles_command(verbose=verbose)
|
168
168
|
|
169
169
|
|
170
170
|
@click.command("register_actions")
|
cornflow/cli/roles.py
CHANGED
cornflow/cli/service.py
CHANGED
@@ -2,8 +2,20 @@ import os
|
|
2
2
|
import subprocess
|
3
3
|
import sys
|
4
4
|
import time
|
5
|
+
import logging
|
5
6
|
from logging import error
|
6
7
|
|
8
|
+
# Configure a logger for the service module
|
9
|
+
logger = logging.getLogger("cornflow.service")
|
10
|
+
logger.setLevel(logging.INFO)
|
11
|
+
|
12
|
+
# Add console handler if not already present
|
13
|
+
if not logger.handlers:
|
14
|
+
handler = logging.StreamHandler(sys.stdout)
|
15
|
+
formatter = logging.Formatter("%(asctime)s [%(name)s] [%(levelname)s] %(message)s")
|
16
|
+
handler.setFormatter(formatter)
|
17
|
+
logger.addHandler(handler)
|
18
|
+
logger.propagate = False
|
7
19
|
|
8
20
|
import click
|
9
21
|
from .utils import get_db_conn
|
@@ -89,9 +101,10 @@ def init_cornflow_service():
|
|
89
101
|
|
90
102
|
external_app_lib = import_module(external_app_module)
|
91
103
|
app = external_app_lib.create_wsgi_app(environment, cornflow_db_conn)
|
92
|
-
|
93
104
|
with app.app_context():
|
105
|
+
|
94
106
|
_initialize_database(app, external_app_module)
|
107
|
+
|
95
108
|
_create_initial_users(
|
96
109
|
config["auth"],
|
97
110
|
config["cornflow_admin_user"],
|
@@ -101,6 +114,7 @@ def init_cornflow_service():
|
|
101
114
|
config["cornflow_service_email"],
|
102
115
|
config["cornflow_service_pwd"],
|
103
116
|
)
|
117
|
+
|
104
118
|
_sync_with_airflow(
|
105
119
|
config["airflow_url"],
|
106
120
|
config["airflow_user"],
|
@@ -117,6 +131,7 @@ def init_cornflow_service():
|
|
117
131
|
|
118
132
|
def _setup_environment_variables():
|
119
133
|
"""Reads environment variables, sets defaults, and returns config values."""
|
134
|
+
|
120
135
|
environment = os.getenv("FLASK_ENV", "development")
|
121
136
|
os.environ["FLASK_ENV"] = environment
|
122
137
|
|
@@ -218,7 +233,7 @@ def _configure_logging(cornflow_logging):
|
|
218
233
|
if logrotate.returncode != 0:
|
219
234
|
error(f"Error configuring logrotate: {logrotate.stderr}")
|
220
235
|
else:
|
221
|
-
|
236
|
+
logger.info(logrotate.stdout)
|
222
237
|
except Exception as e:
|
223
238
|
error(f"Exception during logrotate configuration: {e}")
|
224
239
|
|
@@ -236,6 +251,7 @@ def _initialize_database(app, external_app_module=None):
|
|
236
251
|
|
237
252
|
Migrate(app=app, db=db, directory=migrations_path)
|
238
253
|
upgrade()
|
254
|
+
logger.info("----------------Migrations applied----------------")
|
239
255
|
access_init_command(verbose=False)
|
240
256
|
|
241
257
|
|
@@ -285,14 +301,21 @@ def _sync_with_airflow(
|
|
285
301
|
|
286
302
|
def _setup_external_app():
|
287
303
|
"""Performs setup steps specific to external applications."""
|
304
|
+
|
288
305
|
os.chdir(MAIN_WD)
|
306
|
+
|
289
307
|
if _register_key():
|
308
|
+
|
290
309
|
prefix = "CUSTOM_SSH_"
|
291
310
|
env_variables = {
|
292
311
|
key: value for key, value in os.environ.items() if key.startswith(prefix)
|
293
312
|
}
|
294
313
|
for _, value in env_variables.items():
|
295
314
|
_register_ssh_host(value)
|
315
|
+
else:
|
316
|
+
logger.info(
|
317
|
+
"************************ NO SSH KEY TO REGISTER ************************"
|
318
|
+
)
|
296
319
|
|
297
320
|
# Install requirements for the external app
|
298
321
|
pip_install_cmd = "$(command -v pip) install --user -r requirements.txt"
|
@@ -301,10 +324,15 @@ def _setup_external_app():
|
|
301
324
|
if result.returncode != 0:
|
302
325
|
error(f"Error installing requirements: {result.stderr}")
|
303
326
|
else:
|
304
|
-
|
327
|
+
logger.info(result.stdout)
|
305
328
|
time.sleep(5) # Consider if this sleep is truly necessary
|
306
329
|
sys.path.append(MAIN_WD)
|
307
330
|
|
331
|
+
# Add .local path to sys.path so pip --user packages can be found
|
332
|
+
local_lib_path = os.path.expanduser("~/.local/lib/python3.12/site-packages")
|
333
|
+
if local_lib_path not in sys.path:
|
334
|
+
sys.path.insert(0, local_lib_path)
|
335
|
+
|
308
336
|
|
309
337
|
def _start_application(external_application, environment, external_app_module=None):
|
310
338
|
"""Starts the Gunicorn server."""
|
@@ -349,4 +377,4 @@ def _register_key():
|
|
349
377
|
os.system(add_key)
|
350
378
|
return True
|
351
379
|
else:
|
352
|
-
return False
|
380
|
+
return False
|
cornflow/commands/access.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import logging
|
1
2
|
import os
|
2
3
|
|
3
4
|
from .actions import register_actions_command
|
@@ -5,18 +6,28 @@ from .permissions import register_base_permissions_command
|
|
5
6
|
from .roles import register_roles_command
|
6
7
|
from .views import register_views_command
|
7
8
|
|
9
|
+
# Configure logger for access
|
10
|
+
logger = logging.getLogger("cornflow.access")
|
11
|
+
|
8
12
|
|
9
13
|
def access_init_command(verbose: bool = False):
|
14
|
+
"""
|
15
|
+
Initialize the access to the system.
|
16
|
+
"""
|
17
|
+
|
10
18
|
external = int(os.getenv("EXTERNAL_APP", 0))
|
11
19
|
external_app = os.getenv("EXTERNAL_APP_MODULE", "external_app")
|
12
20
|
|
13
21
|
register_actions_command(verbose)
|
14
|
-
register_roles_command(verbose)
|
15
22
|
|
16
|
-
register_views_command(verbose=verbose)
|
17
23
|
if external != 0:
|
24
|
+
register_roles_command(external_app=external_app, verbose=verbose)
|
18
25
|
register_views_command(external_app=external_app, verbose=verbose)
|
26
|
+
else:
|
27
|
+
register_roles_command(verbose=verbose)
|
28
|
+
register_views_command(verbose=verbose)
|
19
29
|
|
20
|
-
register_base_permissions_command(verbose=verbose)
|
21
30
|
if external != 0:
|
22
31
|
register_base_permissions_command(external_app=external_app, verbose=verbose)
|
32
|
+
else:
|
33
|
+
register_base_permissions_command(verbose=verbose)
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import sys
|
2
|
+
from importlib import import_module
|
3
|
+
|
4
|
+
from flask import current_app
|
5
|
+
|
6
|
+
from cornflow.endpoints import resources, alarms_resources
|
7
|
+
from cornflow.models import RoleModel
|
8
|
+
from cornflow.shared.const import (
|
9
|
+
EXTRA_PERMISSION_ASSIGNATION,
|
10
|
+
ALL_DEFAULT_ROLES,
|
11
|
+
)
|
12
|
+
from cornflow.shared.const import ROLES_MAP
|
13
|
+
|
14
|
+
|
15
|
+
def get_all_external(external_app):
|
16
|
+
"""
|
17
|
+
Get all resources and extra permissions.
|
18
|
+
external_app: If provided, it will get the resources and extra permissions for the external app.
|
19
|
+
"""
|
20
|
+
if external_app is None:
|
21
|
+
resources_to_register = resources
|
22
|
+
extra_permissions = EXTRA_PERMISSION_ASSIGNATION
|
23
|
+
if current_app.config["ALARMS_ENDPOINTS"]:
|
24
|
+
resources_to_register = resources + alarms_resources
|
25
|
+
else:
|
26
|
+
sys.path.append("./")
|
27
|
+
external_module = import_module(external_app)
|
28
|
+
try:
|
29
|
+
extra_permissions = (
|
30
|
+
EXTRA_PERMISSION_ASSIGNATION
|
31
|
+
+ external_module.shared.const.EXTRA_PERMISSION_ASSIGNATION
|
32
|
+
)
|
33
|
+
except AttributeError:
|
34
|
+
extra_permissions = EXTRA_PERMISSION_ASSIGNATION
|
35
|
+
|
36
|
+
if current_app.config["ALARMS_ENDPOINTS"]:
|
37
|
+
resources_to_register = (
|
38
|
+
external_module.endpoints.resources + resources + alarms_resources
|
39
|
+
)
|
40
|
+
else:
|
41
|
+
resources_to_register = external_module.endpoints.resources + resources
|
42
|
+
return resources_to_register, extra_permissions
|
43
|
+
|
44
|
+
|
45
|
+
def get_all_resources(resources_to_register):
|
46
|
+
"""
|
47
|
+
Get all resources and roles with access.
|
48
|
+
resources_to_register: List of resources to register.
|
49
|
+
"""
|
50
|
+
|
51
|
+
resources_roles_with_access = {
|
52
|
+
resource["endpoint"]: resource["resource"].ROLES_WITH_ACCESS
|
53
|
+
for resource in resources_to_register
|
54
|
+
}
|
55
|
+
|
56
|
+
return resources_roles_with_access
|
57
|
+
|
58
|
+
|
59
|
+
def get_new_roles_to_add(extra_permissions, resources_roles_with_access):
|
60
|
+
"""
|
61
|
+
Get the new roles to add.
|
62
|
+
extra_permissions: List of extra permissions.
|
63
|
+
resources_roles_with_access: Dictionary of resources and roles with access.
|
64
|
+
"""
|
65
|
+
|
66
|
+
roles_with_access = list(
|
67
|
+
set([role for roles in resources_roles_with_access.values() for role in roles])
|
68
|
+
)
|
69
|
+
roles_in_extra_permissions = [role for role, _, _ in extra_permissions]
|
70
|
+
roles_with_access = list(set(roles_with_access + roles_in_extra_permissions))
|
71
|
+
|
72
|
+
# Add all default roles that are referenced in BASE_PERMISSION_ASSIGNATION
|
73
|
+
roles_with_access = list(set(roles_with_access + ALL_DEFAULT_ROLES))
|
74
|
+
|
75
|
+
# We extract the existing roles in the database
|
76
|
+
existing_roles = [role.id for role in RoleModel.get_all_objects()]
|
77
|
+
new_roles_to_add = []
|
78
|
+
|
79
|
+
for role_id in roles_with_access:
|
80
|
+
if role_id not in existing_roles:
|
81
|
+
if role_id in ALL_DEFAULT_ROLES:
|
82
|
+
# Create standard role with predefined name
|
83
|
+
role_name = ROLES_MAP[role_id]
|
84
|
+
new_role = RoleModel(
|
85
|
+
{
|
86
|
+
"id": role_id,
|
87
|
+
"name": role_name,
|
88
|
+
}
|
89
|
+
)
|
90
|
+
else:
|
91
|
+
# Create custom role with custom_role_<id> name
|
92
|
+
new_role = RoleModel(
|
93
|
+
{
|
94
|
+
"id": role_id,
|
95
|
+
"name": f"custom_role_{role_id}",
|
96
|
+
}
|
97
|
+
)
|
98
|
+
new_roles_to_add.append(new_role)
|
99
|
+
|
100
|
+
return new_roles_to_add
|
cornflow/commands/permissions.py
CHANGED
@@ -1,110 +1,92 @@
|
|
1
|
-
import
|
2
|
-
from
|
1
|
+
from flask import current_app
|
2
|
+
from sqlalchemy.exc import DBAPIError, IntegrityError
|
3
3
|
|
4
|
+
from cornflow.commands.auxiliar import (
|
5
|
+
get_all_external,
|
6
|
+
get_all_resources,
|
7
|
+
)
|
8
|
+
from cornflow.models import ViewModel, PermissionViewRoleModel
|
9
|
+
from cornflow.shared import db
|
10
|
+
from cornflow.shared.const import ALL_DEFAULT_ROLES, GET_ACTION
|
4
11
|
from cornflow.shared.const import (
|
5
12
|
BASE_PERMISSION_ASSIGNATION,
|
6
|
-
EXTRA_PERMISSION_ASSIGNATION,
|
7
|
-
ROLES_MAP,
|
8
|
-
GET_ACTION,
|
9
|
-
PATCH_ACTION,
|
10
|
-
POST_ACTION,
|
11
|
-
PUT_ACTION,
|
12
|
-
DELETE_ACTION,
|
13
13
|
)
|
14
|
-
from cornflow.models import ViewModel, PermissionViewRoleModel, RoleModel
|
15
|
-
from cornflow.shared import db
|
16
|
-
from flask import current_app
|
17
|
-
from sqlalchemy.exc import DBAPIError, IntegrityError
|
18
14
|
|
19
15
|
|
20
16
|
def register_base_permissions_command(external_app: str = None, verbose: bool = False):
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
17
|
+
"""
|
18
|
+
Register base permissions for the application.
|
19
|
+
external_app: If provided, it will register the permissions for the external app.
|
20
|
+
verbose: If True, it will print the permissions that are being registered.
|
21
|
+
"""
|
22
|
+
# Get all resources and extra permissions
|
23
|
+
resources_to_register, extra_permissions = get_all_external(external_app)
|
24
|
+
# Get all views in the database
|
25
|
+
views_in_db = {view.name: view.id for view in ViewModel.get_all_objects()}
|
26
|
+
permissions_in_db, permissions_in_db_keys = get_db_permissions()
|
27
|
+
# Get all resources and roles with access
|
28
|
+
resources_roles_with_access = get_all_resources(resources_to_register)
|
29
|
+
# Get the new roles and base permissions assignation
|
30
|
+
base_permissions_assignation = get_base_permissions(resources_roles_with_access)
|
31
|
+
# Get the permissions to register and delete
|
32
|
+
permissions_tuples = get_permissions_in_code_as_tuples(
|
33
|
+
resources_to_register,
|
34
|
+
views_in_db,
|
35
|
+
base_permissions_assignation,
|
36
|
+
extra_permissions,
|
37
|
+
)
|
38
|
+
permissions_to_register = get_permissions_to_register(
|
39
|
+
permissions_tuples, permissions_in_db_keys
|
40
|
+
)
|
41
|
+
permissions_to_delete = get_permissions_to_delete(
|
42
|
+
permissions_tuples, resources_roles_with_access.keys(), permissions_in_db
|
43
|
+
)
|
44
|
+
|
45
|
+
# Save the new permissions in the data
|
46
|
+
save_and_delete_permissions(permissions_to_register, permissions_to_delete)
|
47
|
+
|
48
|
+
if len(permissions_to_register) > 0:
|
49
|
+
current_app.logger.info(f"Permissions registered: {permissions_to_register}")
|
31
50
|
else:
|
32
|
-
|
33
|
-
exit()
|
51
|
+
current_app.logger.info("No new permissions to register")
|
34
52
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
]
|
40
|
-
resources_names = [resource["endpoint"] for resource in resources_to_register]
|
41
|
-
roles_in_db = [role.name for role in RoleModel.get_all_objects()]
|
42
|
-
# Check which roles are not in ROLES_MAP
|
43
|
-
roles_not_in_map = [role for role in roles_in_db if role not in ROLES_MAP.keys()]
|
44
|
-
complete_base_assignation = BASE_PERMISSION_ASSIGNATION.copy()
|
45
|
-
if len(roles_not_in_map) > 0:
|
46
|
-
# We add to the complete_base_assignation the roles that are not in ROLES_MAP
|
47
|
-
for role in roles_not_in_map:
|
48
|
-
for action in [
|
49
|
-
GET_ACTION,
|
50
|
-
PATCH_ACTION,
|
51
|
-
POST_ACTION,
|
52
|
-
PUT_ACTION,
|
53
|
-
DELETE_ACTION,
|
54
|
-
]:
|
55
|
-
complete_base_assignation.append((role, action))
|
56
|
-
|
57
|
-
# Create base permissions
|
58
|
-
permissions_in_app = [
|
59
|
-
PermissionViewRoleModel(
|
60
|
-
{
|
61
|
-
"role_id": role,
|
62
|
-
"action_id": action,
|
63
|
-
"api_view_id": views_in_db[view["endpoint"]],
|
64
|
-
}
|
65
|
-
)
|
66
|
-
for role, action in complete_base_assignation
|
67
|
-
for view in resources_to_register
|
68
|
-
if role in view["resource"].ROLES_WITH_ACCESS
|
69
|
-
] + [
|
70
|
-
PermissionViewRoleModel(
|
71
|
-
{
|
72
|
-
"role_id": role,
|
73
|
-
"action_id": action,
|
74
|
-
"api_view_id": views_in_db[endpoint],
|
75
|
-
}
|
76
|
-
)
|
77
|
-
for role, action, endpoint in EXTRA_PERMISSION_ASSIGNATION
|
78
|
-
]
|
53
|
+
if len(permissions_to_delete) > 0:
|
54
|
+
current_app.logger.info(f"Permissions deleted: {permissions_to_delete}")
|
55
|
+
else:
|
56
|
+
current_app.logger.info("No permissions to delete")
|
79
57
|
|
80
|
-
permissions_in_app_keys = [
|
81
|
-
(perm.role_id, perm.action_id, perm.api_view_id) for perm in permissions_in_app
|
82
|
-
]
|
83
58
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
59
|
+
def save_new_roles(new_roles_to_add):
|
60
|
+
"""
|
61
|
+
Save the new roles in the database.
|
62
|
+
new_roles_to_add: List of new roles to add.
|
63
|
+
"""
|
64
|
+
if len(new_roles_to_add) > 0:
|
65
|
+
db.session.bulk_save_objects(new_roles_to_add)
|
66
|
+
try:
|
67
|
+
db.session.commit()
|
68
|
+
except IntegrityError as e:
|
69
|
+
db.session.rollback()
|
70
|
+
current_app.logger.error(
|
71
|
+
f"Integrity error on base permissions register: {e}"
|
72
|
+
)
|
73
|
+
except DBAPIError as e:
|
74
|
+
db.session.rollback()
|
75
|
+
current_app.logger.error(f"Unknown error on base permissions register: {e}")
|
90
76
|
|
91
|
-
permissions_to_delete = [
|
92
|
-
permission
|
93
|
-
for permission in permissions_in_db
|
94
|
-
if (permission.role_id, permission.action_id, permission.api_view_id)
|
95
|
-
not in permissions_in_app_keys
|
96
|
-
and permission.api_view.name in resources_names
|
97
|
-
]
|
98
77
|
|
78
|
+
def save_and_delete_permissions(permissions_to_register, permissions_to_delete):
|
79
|
+
"""
|
80
|
+
Save and delete permissions in the database.
|
81
|
+
permissions_to_register: List of permissions to register.
|
82
|
+
permissions_to_delete: List of permissions to delete.
|
83
|
+
"""
|
99
84
|
if len(permissions_to_register) > 0:
|
100
85
|
db.session.bulk_save_objects(permissions_to_register)
|
101
86
|
|
102
|
-
# TODO: for now the permission are not going to get deleted just in case.
|
103
|
-
# We are just going to register new permissions
|
104
87
|
if len(permissions_to_delete) > 0:
|
105
88
|
for permission in permissions_to_delete:
|
106
89
|
db.session.delete(permission)
|
107
|
-
|
108
90
|
try:
|
109
91
|
db.session.commit()
|
110
92
|
except IntegrityError as e:
|
@@ -127,25 +109,107 @@ def register_base_permissions_command(external_app: str = None, verbose: bool =
|
|
127
109
|
f"Unknown error on base permissions sequence updating: {e}"
|
128
110
|
)
|
129
111
|
|
130
|
-
if verbose:
|
131
|
-
if len(permissions_to_register) > 0:
|
132
|
-
current_app.logger.info(
|
133
|
-
f"Permissions registered: {permissions_to_register}"
|
134
|
-
)
|
135
|
-
else:
|
136
|
-
current_app.logger.info("No new permissions to register")
|
137
112
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
113
|
+
def get_permissions_to_delete(permissions_tuples, resources_names, permissions_in_db):
|
114
|
+
"""
|
115
|
+
Get the permissions to delete.
|
116
|
+
"""
|
117
|
+
permissions_to_delete = [
|
118
|
+
permission
|
119
|
+
for permission in permissions_in_db
|
120
|
+
if (permission.role_id, permission.action_id, permission.api_view_id)
|
121
|
+
not in permissions_tuples
|
122
|
+
]
|
123
|
+
|
124
|
+
return permissions_to_delete
|
125
|
+
|
126
|
+
|
127
|
+
def get_permissions_to_register(permissions_tuples, permissions_in_db_keys):
|
128
|
+
"""
|
129
|
+
Get the permissions to register.
|
130
|
+
"""
|
131
|
+
# Convert set of tuples to list of PermissionViewRoleModel objects
|
132
|
+
return [
|
133
|
+
PermissionViewRoleModel(
|
134
|
+
{
|
135
|
+
"role_id": role_id,
|
136
|
+
"action_id": action_id,
|
137
|
+
"api_view_id": api_view_id,
|
138
|
+
}
|
139
|
+
)
|
140
|
+
for role_id, action_id, api_view_id in permissions_tuples
|
141
|
+
if (role_id, action_id, api_view_id) not in permissions_in_db_keys
|
142
|
+
]
|
143
|
+
|
144
|
+
|
145
|
+
def get_permissions_in_code_as_tuples(
|
146
|
+
resources_to_register, views_in_db, base_permissions_assignation, extra_permissions
|
147
|
+
):
|
148
|
+
"""
|
149
|
+
Get the permissions in code as tuples.
|
150
|
+
"""
|
151
|
+
# Create base permissions using a set to avoid duplicates
|
152
|
+
permissions_tuples = set()
|
153
|
+
|
154
|
+
# Add permissions from ROLES_WITH_ACCESS
|
155
|
+
for role, action in base_permissions_assignation:
|
156
|
+
for view in resources_to_register:
|
157
|
+
if role in view["resource"].ROLES_WITH_ACCESS:
|
158
|
+
permissions_tuples.add((role, action, views_in_db[view["endpoint"]]))
|
159
|
+
|
160
|
+
# Add permissions from extra_permissions
|
161
|
+
for role, action, endpoint in extra_permissions:
|
162
|
+
if endpoint in views_in_db:
|
163
|
+
permissions_tuples.add((role, action, views_in_db[endpoint]))
|
164
|
+
|
165
|
+
return permissions_tuples
|
166
|
+
|
167
|
+
|
168
|
+
def get_base_permissions(resources_roles_with_access):
|
169
|
+
"""
|
170
|
+
Get the new roles and base permissions assignation.
|
171
|
+
new_roles_to_add: List of new roles to add.
|
172
|
+
resources_roles_with_access: Dictionary of resources and roles with access.
|
173
|
+
"""
|
174
|
+
# Get all custom roles (both new and existing) that appear in ROLES_WITH_ACCESS
|
175
|
+
all_custom_roles_in_access = set(
|
176
|
+
[
|
177
|
+
role
|
178
|
+
for roles in resources_roles_with_access.values()
|
179
|
+
for role in roles
|
180
|
+
if role not in ALL_DEFAULT_ROLES
|
181
|
+
]
|
182
|
+
)
|
183
|
+
|
184
|
+
# Create extended permission assignation including all custom roles
|
185
|
+
# For custom roles (not in ALL_DEFAULT_ROLES), only grant GET access
|
186
|
+
base_permissions_assignation = BASE_PERMISSION_ASSIGNATION + [
|
187
|
+
(custom_role, GET_ACTION) for custom_role in all_custom_roles_in_access
|
188
|
+
]
|
189
|
+
|
190
|
+
return base_permissions_assignation
|
191
|
+
|
192
|
+
|
193
|
+
def get_db_permissions():
|
194
|
+
"""
|
195
|
+
Get all permissions in the database.
|
196
|
+
"""
|
197
|
+
permissions_in_db = [perm for perm in PermissionViewRoleModel.get_all_objects()]
|
198
|
+
permissions_in_db_keys = [
|
199
|
+
(perm.role_id, perm.action_id, perm.api_view_id) for perm in permissions_in_db
|
200
|
+
]
|
142
201
|
|
143
|
-
return
|
202
|
+
return permissions_in_db, permissions_in_db_keys
|
144
203
|
|
145
204
|
|
146
205
|
def register_dag_permissions_command(
|
147
206
|
open_deployment: int = None, verbose: bool = False
|
148
207
|
):
|
208
|
+
"""
|
209
|
+
Register DAG permissions.
|
210
|
+
open_deployment: If 1, it will register the permissions for the open deployment.
|
211
|
+
verbose: If True, it will print the permissions that are being registered.
|
212
|
+
"""
|
149
213
|
|
150
214
|
from flask import current_app
|
151
215
|
from sqlalchemy.exc import DBAPIError, IntegrityError
|
cornflow/commands/roles.py
CHANGED
@@ -1,22 +1,23 @@
|
|
1
|
-
def register_roles_command(verbose: bool = True):
|
1
|
+
def register_roles_command(external_app: str = None, verbose: bool = True):
|
2
2
|
|
3
3
|
from sqlalchemy.exc import DBAPIError, IntegrityError
|
4
4
|
from flask import current_app
|
5
5
|
|
6
|
-
from cornflow.models import RoleModel
|
7
|
-
from cornflow.shared.const import ROLES_MAP
|
8
6
|
from cornflow.shared import db
|
7
|
+
from cornflow.commands.auxiliar import (
|
8
|
+
get_all_external,
|
9
|
+
get_all_resources,
|
10
|
+
get_new_roles_to_add,
|
11
|
+
)
|
9
12
|
|
10
|
-
|
13
|
+
resources_to_register, extra_permissions = get_all_external(external_app)
|
14
|
+
resources_roles_with_access = get_all_resources(resources_to_register)
|
15
|
+
new_roles_to_add = get_new_roles_to_add(
|
16
|
+
extra_permissions, resources_roles_with_access
|
17
|
+
)
|
11
18
|
|
12
|
-
|
13
|
-
|
14
|
-
for key, value in ROLES_MAP.items()
|
15
|
-
if value not in roles_registered
|
16
|
-
]
|
17
|
-
|
18
|
-
if len(roles_to_register) > 0:
|
19
|
-
db.session.bulk_save_objects(roles_to_register)
|
19
|
+
if len(new_roles_to_add) > 0:
|
20
|
+
db.session.bulk_save_objects(new_roles_to_add)
|
20
21
|
|
21
22
|
try:
|
22
23
|
db.session.commit()
|
@@ -38,8 +39,8 @@ def register_roles_command(verbose: bool = True):
|
|
38
39
|
current_app.logger.error(f"Unknown error on roles sequence updating: {e}")
|
39
40
|
|
40
41
|
if verbose:
|
41
|
-
if len(
|
42
|
-
current_app.logger.info(f"Roles registered: {
|
42
|
+
if len(new_roles_to_add) > 0:
|
43
|
+
current_app.logger.info(f"Roles registered: {new_roles_to_add}")
|
43
44
|
else:
|
44
45
|
current_app.logger.info("No new roles to be registered")
|
45
46
|
|