cornflow 1.2.3a1__py3-none-any.whl → 1.2.3a3__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/commands/permissions.py +26 -2
- cornflow/shared/const.py +1 -1
- cornflow/tests/unit/test_commands.py +103 -0
- {cornflow-1.2.3a1.dist-info → cornflow-1.2.3a3.dist-info}/METADATA +1 -1
- {cornflow-1.2.3a1.dist-info → cornflow-1.2.3a3.dist-info}/RECORD +8 -8
- {cornflow-1.2.3a1.dist-info → cornflow-1.2.3a3.dist-info}/WHEEL +0 -0
- {cornflow-1.2.3a1.dist-info → cornflow-1.2.3a3.dist-info}/entry_points.txt +0 -0
- {cornflow-1.2.3a1.dist-info → cornflow-1.2.3a3.dist-info}/top_level.txt +0 -0
cornflow/commands/permissions.py
CHANGED
@@ -4,8 +4,14 @@ from importlib import import_module
|
|
4
4
|
from cornflow.shared.const import (
|
5
5
|
BASE_PERMISSION_ASSIGNATION,
|
6
6
|
EXTRA_PERMISSION_ASSIGNATION,
|
7
|
+
ROLES_MAP,
|
8
|
+
GET_ACTION,
|
9
|
+
PATCH_ACTION,
|
10
|
+
POST_ACTION,
|
11
|
+
PUT_ACTION,
|
12
|
+
DELETE_ACTION,
|
7
13
|
)
|
8
|
-
from cornflow.models import ViewModel, PermissionViewRoleModel
|
14
|
+
from cornflow.models import ViewModel, PermissionViewRoleModel, RoleModel
|
9
15
|
from cornflow.shared import db
|
10
16
|
from flask import current_app
|
11
17
|
from sqlalchemy.exc import DBAPIError, IntegrityError
|
@@ -14,6 +20,7 @@ from sqlalchemy.exc import DBAPIError, IntegrityError
|
|
14
20
|
def register_base_permissions_command(external_app: str = None, verbose: bool = False):
|
15
21
|
if external_app is None:
|
16
22
|
from cornflow.endpoints import resources, alarms_resources
|
23
|
+
|
17
24
|
resources_to_register = resources
|
18
25
|
if current_app.config["ALARMS_ENDPOINTS"]:
|
19
26
|
resources_to_register = resources + alarms_resources
|
@@ -31,6 +38,23 @@ def register_base_permissions_command(external_app: str = None, verbose: bool =
|
|
31
38
|
(perm.role_id, perm.action_id, perm.api_view_id) for perm in permissions_in_db
|
32
39
|
]
|
33
40
|
resources_names = [resource["endpoint"] for resource in resources_to_register]
|
41
|
+
roles_in_db = [role.id for role in RoleModel.get_all_objects()]
|
42
|
+
# Check which roles are not in ROLES_MAP
|
43
|
+
roles_not_in_map = [
|
44
|
+
role_id for role_id in roles_in_db if role_id not in ROLES_MAP.keys()
|
45
|
+
]
|
46
|
+
complete_base_assignation = BASE_PERMISSION_ASSIGNATION.copy()
|
47
|
+
if len(roles_not_in_map) > 0:
|
48
|
+
# We add to the complete_base_assignation the roles that are not in ROLES_MAP
|
49
|
+
for role_id in roles_not_in_map:
|
50
|
+
for action in [
|
51
|
+
GET_ACTION,
|
52
|
+
PATCH_ACTION,
|
53
|
+
POST_ACTION,
|
54
|
+
PUT_ACTION,
|
55
|
+
DELETE_ACTION,
|
56
|
+
]:
|
57
|
+
complete_base_assignation.append((role_id, action))
|
34
58
|
|
35
59
|
# Create base permissions
|
36
60
|
permissions_in_app = [
|
@@ -41,7 +65,7 @@ def register_base_permissions_command(external_app: str = None, verbose: bool =
|
|
41
65
|
"api_view_id": views_in_db[view["endpoint"]],
|
42
66
|
}
|
43
67
|
)
|
44
|
-
for role, action in
|
68
|
+
for role, action in complete_base_assignation
|
45
69
|
for view in resources_to_register
|
46
70
|
if role in view["resource"].ROLES_WITH_ACCESS
|
47
71
|
] + [
|
cornflow/shared/const.py
CHANGED
@@ -584,3 +584,106 @@ class TestCommands(TestCase):
|
|
584
584
|
finally:
|
585
585
|
# Restore original ROLES_WITH_ACCESS to avoid affecting other tests
|
586
586
|
ExampleDataListEndpoint.ROLES_WITH_ACCESS = original_roles
|
587
|
+
|
588
|
+
def test_custom_role_permissions_are_preserved(self):
|
589
|
+
"""
|
590
|
+
Test that custom roles (not in ROLES_MAP) are automatically detected
|
591
|
+
and assigned complete permissions during synchronization.
|
592
|
+
|
593
|
+
This test verifies that when permissions are synchronized:
|
594
|
+
1. Custom roles in the database are automatically detected
|
595
|
+
2. They are assigned all actions (GET, PATCH, POST, PUT, DELETE)
|
596
|
+
3. These permissions are created for all endpoints where the role has access
|
597
|
+
"""
|
598
|
+
# First, initialize the access system normally
|
599
|
+
self.runner.invoke(access_init)
|
600
|
+
|
601
|
+
# Get a view to work with
|
602
|
+
from cornflow.models import ViewModel, PermissionViewRoleModel, RoleModel
|
603
|
+
|
604
|
+
view = ViewModel.query.filter_by(name="example-data").first()
|
605
|
+
self.assertIsNotNone(view, "example-data view should exist")
|
606
|
+
|
607
|
+
# Create a custom role that is NOT in ROLES_MAP
|
608
|
+
custom_role_id = 999 # Use an ID that's not in ROLES_MAP
|
609
|
+
custom_role = RoleModel({"id": custom_role_id, "name": "custom_role"})
|
610
|
+
custom_role.save()
|
611
|
+
|
612
|
+
# Temporarily add the custom role to ExampleDataListEndpoint ROLES_WITH_ACCESS
|
613
|
+
from cornflow.endpoints.example_data import ExampleDataListEndpoint
|
614
|
+
|
615
|
+
original_roles = ExampleDataListEndpoint.ROLES_WITH_ACCESS.copy()
|
616
|
+
ExampleDataListEndpoint.ROLES_WITH_ACCESS = original_roles + [custom_role_id]
|
617
|
+
|
618
|
+
try:
|
619
|
+
# Count permissions before synchronization
|
620
|
+
perms_before = PermissionViewRoleModel.query.filter_by(
|
621
|
+
role_id=custom_role_id, api_view_id=view.id
|
622
|
+
).count()
|
623
|
+
self.assertEqual(
|
624
|
+
0, perms_before, "No custom permissions should exist initially"
|
625
|
+
)
|
626
|
+
|
627
|
+
# Run permission synchronization - this should auto-detect the custom role
|
628
|
+
self.runner.invoke(register_base_assignations, ["-v"])
|
629
|
+
|
630
|
+
# Verify that ALL actions have been assigned to the custom role
|
631
|
+
from cornflow.shared.const import (
|
632
|
+
GET_ACTION,
|
633
|
+
PATCH_ACTION,
|
634
|
+
POST_ACTION,
|
635
|
+
PUT_ACTION,
|
636
|
+
DELETE_ACTION,
|
637
|
+
)
|
638
|
+
|
639
|
+
expected_actions = [
|
640
|
+
GET_ACTION,
|
641
|
+
PATCH_ACTION,
|
642
|
+
POST_ACTION,
|
643
|
+
PUT_ACTION,
|
644
|
+
DELETE_ACTION,
|
645
|
+
]
|
646
|
+
|
647
|
+
for action in expected_actions:
|
648
|
+
permission = PermissionViewRoleModel.query.filter_by(
|
649
|
+
role_id=custom_role_id, action_id=action, api_view_id=view.id
|
650
|
+
).first()
|
651
|
+
self.assertIsNotNone(
|
652
|
+
permission,
|
653
|
+
f"Custom role should have permission for action {action}. "
|
654
|
+
f"The system should auto-detect custom roles and assign complete permissions.",
|
655
|
+
)
|
656
|
+
|
657
|
+
# Verify total count of permissions for custom role
|
658
|
+
total_perms = PermissionViewRoleModel.query.filter_by(
|
659
|
+
role_id=custom_role_id, api_view_id=view.id
|
660
|
+
).count()
|
661
|
+
self.assertEqual(
|
662
|
+
len(expected_actions),
|
663
|
+
total_perms,
|
664
|
+
f"Custom role should have {len(expected_actions)} permissions (all actions)",
|
665
|
+
)
|
666
|
+
|
667
|
+
# Test that running sync again doesn't duplicate permissions
|
668
|
+
self.runner.invoke(register_base_assignations, ["-v"])
|
669
|
+
|
670
|
+
total_perms_after_second_sync = PermissionViewRoleModel.query.filter_by(
|
671
|
+
role_id=custom_role_id, api_view_id=view.id
|
672
|
+
).count()
|
673
|
+
self.assertEqual(
|
674
|
+
len(expected_actions),
|
675
|
+
total_perms_after_second_sync,
|
676
|
+
"Permissions should not be duplicated on subsequent syncs",
|
677
|
+
)
|
678
|
+
|
679
|
+
finally:
|
680
|
+
# Clean up
|
681
|
+
# Delete permissions first (due to foreign key constraints)
|
682
|
+
permissions_to_delete = PermissionViewRoleModel.query.filter_by(
|
683
|
+
role_id=custom_role_id
|
684
|
+
).all()
|
685
|
+
for perm in permissions_to_delete:
|
686
|
+
perm.delete()
|
687
|
+
custom_role.delete()
|
688
|
+
# Restore original ROLES_WITH_ACCESS
|
689
|
+
ExampleDataListEndpoint.ROLES_WITH_ACCESS = original_roles
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cornflow
|
3
|
-
Version: 1.2.
|
3
|
+
Version: 1.2.3a3
|
4
4
|
Summary: cornflow is an open source multi-solver optimization server with a REST API built using flask.
|
5
5
|
Home-page: https://github.com/baobabsoluciones/cornflow
|
6
6
|
Author: baobab soluciones
|
@@ -32,7 +32,7 @@ cornflow/commands/access.py,sha256=NTZJFF9la8TDuMcD_ISQtJTj-wtM2p1dddokQJHtkj0,7
|
|
32
32
|
cornflow/commands/actions.py,sha256=4AwgAmyI6VeaugkISvTlNGrIzMMU_-ZB3MhwDD_CIEA,1544
|
33
33
|
cornflow/commands/cleanup.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
34
|
cornflow/commands/dag.py,sha256=AtagFGnB_ucfO0qUawDgd4iRoBCVc-RiOs08DqXSwXM,3786
|
35
|
-
cornflow/commands/permissions.py,sha256=
|
35
|
+
cornflow/commands/permissions.py,sha256=f6UMB1dj4KBXhrCXalcOdiQlDUldbbmslI6yTrK-_VM,7439
|
36
36
|
cornflow/commands/roles.py,sha256=Oux-UkswkQ74zqaMEJYIEsZpQZGBcGaSahVzx9feAHU,1516
|
37
37
|
cornflow/commands/schemas.py,sha256=40dZSJ2nEqBa7Crb6DbFmnclT5e8ljAIjscOgHr9lhk,1970
|
38
38
|
cornflow/commands/users.py,sha256=2YTbNYY5kZL6ujxGP4fyYgqtv5uuVGdkLR31n7OFFaE,2477
|
@@ -119,7 +119,7 @@ cornflow/schemas/user_role.py,sha256=e5y6RgdZZtLqD-h2B3sa5WokI5-pT78tWw85IG34I74
|
|
119
119
|
cornflow/schemas/view.py,sha256=ctq9Y1TmjrWdyOqgDYeEx7qbbuNLKfSiNOlFTlXmpaw,429
|
120
120
|
cornflow/shared/__init__.py,sha256=1ahcBwWOsSjGI4FEm77JBQjitBdBszOncKcEMjzwGYE,29
|
121
121
|
cornflow/shared/compress.py,sha256=pohQaGs1xbH8CN6URIH6BAHA--pFq7Hmjz8oI3c3B5c,1347
|
122
|
-
cornflow/shared/const.py,sha256=
|
122
|
+
cornflow/shared/const.py,sha256=06VjXJ1MxSc7MrmWMZD95N0VCLjiNqXIE3o1a-xd9n0,3555
|
123
123
|
cornflow/shared/email.py,sha256=QNDDMv86LZObkevSCyUbLQeR2UD3zWScPIr82NDzYHQ,3437
|
124
124
|
cornflow/shared/exceptions.py,sha256=E82488IiwTXCv8iwrnGvkTonhJcwbeE5ARO4Zsmhl2c,6966
|
125
125
|
cornflow/shared/licenses.py,sha256=Lc71Jw2NxVTFWtoXdQ9wJX_o3BDfYg1xVoehDXvnCkQ,1328
|
@@ -148,7 +148,7 @@ cornflow/tests/unit/test_apiview.py,sha256=03M1GsQRVK7zqmslhOJXr4lLDLY2gMAgg86nk
|
|
148
148
|
cornflow/tests/unit/test_application.py,sha256=ZVmTQDUOkPRxHqt6mWU9G_lQ3jJNMJR0cx7IkLMFGrU,1715
|
149
149
|
cornflow/tests/unit/test_cases.py,sha256=Ez9dxlZL-SUf9DW9b_A_qPowHqUZ-TA73DMOzeBeLIU,37718
|
150
150
|
cornflow/tests/unit/test_cli.py,sha256=E2w-Lzgx_k__0mYwlbg2z80_z9nwPZKI0CbgyGmpQRY,18775
|
151
|
-
cornflow/tests/unit/test_commands.py,sha256=
|
151
|
+
cornflow/tests/unit/test_commands.py,sha256=JaV_RX9VNaYj_3_QKHZmxct5irfA9GnQLKmpO002P1Y,23002
|
152
152
|
cornflow/tests/unit/test_dags.py,sha256=XsOi5bBJQdQz3DmYAVJf1myoAsRyBBdmku-xBr0Bku0,13386
|
153
153
|
cornflow/tests/unit/test_data_checks.py,sha256=6s50d1iuRTUcAYn14oEcRS39ZZ6E9ussU4YpkpYhtC4,8612
|
154
154
|
cornflow/tests/unit/test_example_data.py,sha256=D-Tgnqw7NZlnBXaDcUU0reNhAca5JlJP2Sdn3KdS4Sw,4127
|
@@ -169,8 +169,8 @@ cornflow/tests/unit/test_tables.py,sha256=SW_K8LRLwR1nB0uH8CPQCjeN8Gei-TasAgkOin
|
|
169
169
|
cornflow/tests/unit/test_token.py,sha256=PZ11b46UCQpCESsRiAPhpgWkGAsAwKCVNxVQai_kxXM,4199
|
170
170
|
cornflow/tests/unit/test_users.py,sha256=N5tcF5nSncD0F_ZlBxGuS87p6kNS4hUzRLr3_AcnK-o,22802
|
171
171
|
cornflow/tests/unit/tools.py,sha256=ag3sWv2WLi498R1GL5AOUnXqSsszD3UugzLZLC5NqAw,585
|
172
|
-
cornflow-1.2.
|
173
|
-
cornflow-1.2.
|
174
|
-
cornflow-1.2.
|
175
|
-
cornflow-1.2.
|
176
|
-
cornflow-1.2.
|
172
|
+
cornflow-1.2.3a3.dist-info/METADATA,sha256=lwa0AelaIIcefbhB5bES98yk1h4R_r5p17FzhqvIpdE,9529
|
173
|
+
cornflow-1.2.3a3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
174
|
+
cornflow-1.2.3a3.dist-info/entry_points.txt,sha256=q9cPKAFBsmHkERCqQ2JcOTM-tVBLHTl-DGxwCXowAWM,46
|
175
|
+
cornflow-1.2.3a3.dist-info/top_level.txt,sha256=Qj9kLFJW1PLb-ZV2s_aCkQ-Wi5W6KC6fFR-LTBrx-rU,24
|
176
|
+
cornflow-1.2.3a3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|