Skip to content

Commit 918d5b3

Browse files
authored
Do some aesthetic adjustments to role presentation fields (#15153)
* Do some asthetic adjustments to role presentation fields * Correctly test managed setup * Minor migration adjustments
1 parent 158314a commit 918d5b3

File tree

10 files changed

+85
-88
lines changed

10 files changed

+85
-88
lines changed

awx/main/migrations/_dab_rbac.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,12 @@ def setup_managed_role_definitions(apps, schema_editor):
275275
"""
276276
Idepotent method to create or sync the managed role definitions
277277
"""
278-
to_create = settings.ANSIBLE_BASE_ROLE_PRECREATE
278+
to_create = {
279+
'object_admin': '{cls.__name__} Admin',
280+
'org_admin': 'Organization Admin',
281+
'org_children': 'Organization {cls.__name__} Admin',
282+
'special': '{cls.__name__} {action}',
283+
}
279284

280285
ContentType = apps.get_model('contenttypes', 'ContentType')
281286
Permission = apps.get_model('dab_rbac', 'DABPermission')

awx/main/models/rbac.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
# django-rest-framework
1111
from rest_framework.serializers import ValidationError
1212

13+
# crum to impersonate users
14+
from crum import impersonate
15+
1316
# Django
1417
from django.db import models, transaction, connection
1518
from django.db.models.signals import m2m_changed
@@ -553,17 +556,22 @@ def get_role_definition(role):
553556
return
554557
f = obj._meta.get_field(role.role_field)
555558
action_name = f.name.rsplit("_", 1)[0]
556-
rd_name = f'{type(obj).__name__} {action_name.title()} Compat'
559+
model_print = type(obj).__name__
560+
rd_name = f'{model_print} {action_name.title()} Compat'
557561
perm_list = get_role_codenames(role)
558-
defaults = {'content_type_id': role.content_type_id}
559-
try:
560-
rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
561-
except ValidationError:
562-
# This is a tricky case - practically speaking, users should not be allowed to create team roles
563-
# or roles that include the team member permission.
564-
# If we need to create this for compatibility purposes then we will create it as a managed non-editable role
565-
defaults['managed'] = True
566-
rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
562+
defaults = {
563+
'content_type_id': role.content_type_id,
564+
'description': f'Has {action_name.title()} permission to {model_print} for backwards API compatibility',
565+
}
566+
with impersonate(None):
567+
try:
568+
rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
569+
except ValidationError:
570+
# This is a tricky case - practically speaking, users should not be allowed to create team roles
571+
# or roles that include the team member permission.
572+
# If we need to create this for compatibility purposes then we will create it as a managed non-editable role
573+
defaults['managed'] = True
574+
rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
567575
return rd
568576

569577

awx/main/tests/functional/api/test_credential.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test_idempotent_credential_type_setup():
3030

3131

3232
@pytest.mark.django_db
33-
def test_create_user_credential_via_credentials_list(post, get, alice, credentialtype_ssh):
33+
def test_create_user_credential_via_credentials_list(post, get, alice, credentialtype_ssh, setup_managed_roles):
3434
params = {
3535
'credential_type': 1,
3636
'inputs': {'username': 'someusername'},
@@ -81,7 +81,7 @@ def test_credential_validation_error_with_multiple_owner_fields(post, admin, ali
8181

8282

8383
@pytest.mark.django_db
84-
def test_create_user_credential_via_user_credentials_list(post, get, alice, credentialtype_ssh):
84+
def test_create_user_credential_via_user_credentials_list(post, get, alice, credentialtype_ssh, setup_managed_roles):
8585
params = {
8686
'credential_type': 1,
8787
'inputs': {'username': 'someusername'},

awx/main/tests/functional/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
from django.db.models.signals import post_migrate
1818

19+
from awx.main.migrations._dab_rbac import setup_managed_role_definitions
20+
1921
# AWX
2022
from awx.main.models.projects import Project
2123
from awx.main.models.ha import Instance
@@ -90,6 +92,12 @@ def deploy_jobtemplate(project, inventory, credential):
9092
return jt
9193

9294

95+
@pytest.fixture
96+
def setup_managed_roles():
97+
"Run the migration script to pre-create managed role definitions"
98+
setup_managed_role_definitions(apps, None)
99+
100+
93101
@pytest.fixture
94102
def team(organization):
95103
return organization.teams.create(name='test-team')

awx/main/tests/functional/dab_rbac/conftest.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

awx/main/tests/functional/dab_rbac/test_dab_migration.py

Lines changed: 0 additions & 45 deletions
This file was deleted.

awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
@pytest.mark.django_db
13-
def test_managed_roles_created(managed_roles):
13+
def test_managed_roles_created(setup_managed_roles):
1414
"Managed RoleDefinitions are created in post_migration signal, we expect to see them here"
1515
for cls in (JobTemplate, Inventory):
1616
ct = ContentType.objects.get_for_model(cls)
@@ -22,7 +22,7 @@ def test_managed_roles_created(managed_roles):
2222

2323

2424
@pytest.mark.django_db
25-
def test_custom_read_role(admin_user, post, managed_roles):
25+
def test_custom_read_role(admin_user, post, setup_managed_roles):
2626
rd_url = django_reverse('roledefinition-list')
2727
resp = post(
2828
url=rd_url, data={"name": "read role made for test", "content_type": "awx.inventory", "permissions": ['view_inventory']}, user=admin_user, expect=201
@@ -40,7 +40,7 @@ def test_custom_system_roles_prohibited(admin_user, post):
4040

4141

4242
@pytest.mark.django_db
43-
def test_assignment_to_invisible_user(admin_user, alice, rando, inventory, post, managed_roles):
43+
def test_assignment_to_invisible_user(admin_user, alice, rando, inventory, post, setup_managed_roles):
4444
"Alice can not see rando, and so can not give them a role assignment"
4545
rd = RoleDefinition.objects.get(name='Inventory Admin')
4646
rd.give_permission(alice, inventory)
@@ -51,7 +51,7 @@ def test_assignment_to_invisible_user(admin_user, alice, rando, inventory, post,
5151

5252

5353
@pytest.mark.django_db
54-
def test_assign_managed_role(admin_user, alice, rando, inventory, post, managed_roles, organization):
54+
def test_assign_managed_role(admin_user, alice, rando, inventory, post, setup_managed_roles, organization):
5555
rd = RoleDefinition.objects.get(name='Inventory Admin')
5656
rd.give_permission(alice, inventory)
5757
# When alice and rando are members of the same org, they can see each other
@@ -78,7 +78,7 @@ def test_assign_custom_delete_role(admin_user, rando, inventory, delete, patch):
7878

7979

8080
@pytest.mark.django_db
81-
def test_assign_custom_add_role(admin_user, rando, organization, post, managed_roles):
81+
def test_assign_custom_add_role(admin_user, rando, organization, post, setup_managed_roles):
8282
rd, _ = RoleDefinition.objects.get_or_create(
8383
name='inventory-add', permissions=['add_inventory', 'view_organization'], content_type=ContentType.objects.get_for_model(Organization)
8484
)

awx/main/tests/functional/dab_rbac/test_translation_layer.py

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22

33
import pytest
44

5+
from django.contrib.contenttypes.models import ContentType
6+
7+
from crum import impersonate
8+
59
from awx.main.models.rbac import get_role_from_object_role, give_creator_permissions
610
from awx.main.models import User, Organization, WorkflowJobTemplate, WorkflowJobTemplateNode, Team
711
from awx.api.versioning import reverse
812

9-
from ansible_base.rbac.models import RoleUserAssignment
13+
from ansible_base.rbac.models import RoleUserAssignment, RoleDefinition
1014

1115

1216
@pytest.mark.django_db
1317
@pytest.mark.parametrize(
1418
'role_name',
1519
['execution_environment_admin_role', 'project_admin_role', 'admin_role', 'auditor_role', 'read_role', 'execute_role', 'notification_admin_role'],
1620
)
17-
def test_round_trip_roles(organization, rando, role_name, managed_roles):
21+
def test_round_trip_roles(organization, rando, role_name, setup_managed_roles):
1822
"""
1923
Make an assignment with the old-style role,
2024
get the equivelent new role
@@ -28,7 +32,39 @@ def test_round_trip_roles(organization, rando, role_name, managed_roles):
2832

2933

3034
@pytest.mark.django_db
31-
def test_organization_level_permissions(organization, inventory, managed_roles):
35+
def test_role_naming(setup_managed_roles):
36+
qs = RoleDefinition.objects.filter(content_type=ContentType.objects.get(model='jobtemplate'), name__endswith='dmin')
37+
assert qs.count() == 1 # sanity
38+
rd = qs.first()
39+
assert rd.name == 'JobTemplate Admin'
40+
assert rd.description
41+
assert rd.created_by is None
42+
43+
44+
@pytest.mark.django_db
45+
def test_action_role_naming(setup_managed_roles):
46+
qs = RoleDefinition.objects.filter(content_type=ContentType.objects.get(model='jobtemplate'), name__endswith='ecute')
47+
assert qs.count() == 1 # sanity
48+
rd = qs.first()
49+
assert rd.name == 'JobTemplate Execute'
50+
assert rd.description
51+
assert rd.created_by is None
52+
53+
54+
@pytest.mark.django_db
55+
def test_compat_role_naming(setup_managed_roles, job_template, rando, alice):
56+
with impersonate(alice):
57+
job_template.read_role.members.add(rando)
58+
qs = RoleDefinition.objects.filter(content_type=ContentType.objects.get(model='jobtemplate'), name__endswith='ompat')
59+
assert qs.count() == 1 # sanity
60+
rd = qs.first()
61+
assert rd.name == 'JobTemplate Read Compat'
62+
assert rd.description
63+
assert rd.created_by is None
64+
65+
66+
@pytest.mark.django_db
67+
def test_organization_level_permissions(organization, inventory, setup_managed_roles):
3268
u1 = User.objects.create(username='alice')
3369
u2 = User.objects.create(username='bob')
3470

@@ -58,14 +94,14 @@ def test_organization_level_permissions(organization, inventory, managed_roles):
5894

5995

6096
@pytest.mark.django_db
61-
def test_organization_execute_role(organization, rando, managed_roles):
97+
def test_organization_execute_role(organization, rando, setup_managed_roles):
6298
organization.execute_role.members.add(rando)
6399
assert rando in organization.execute_role
64100
assert set(Organization.accessible_objects(rando, 'execute_role')) == set([organization])
65101

66102

67103
@pytest.mark.django_db
68-
def test_workflow_approval_list(get, post, admin_user, managed_roles):
104+
def test_workflow_approval_list(get, post, admin_user, setup_managed_roles):
69105
workflow_job_template = WorkflowJobTemplate.objects.create()
70106
approval_node = WorkflowJobTemplateNode.objects.create(workflow_job_template=workflow_job_template)
71107
url = reverse('api:workflow_job_template_node_create_approval', kwargs={'pk': approval_node.pk, 'version': 'v2'})
@@ -79,14 +115,14 @@ def test_workflow_approval_list(get, post, admin_user, managed_roles):
79115

80116

81117
@pytest.mark.django_db
82-
def test_creator_permission(rando, admin_user, inventory, managed_roles):
118+
def test_creator_permission(rando, admin_user, inventory, setup_managed_roles):
83119
give_creator_permissions(rando, inventory)
84120
assert rando in inventory.admin_role
85121
assert rando in inventory.admin_role.members.all()
86122

87123

88124
@pytest.mark.django_db
89-
def test_team_team_read_role(rando, team, admin_user, post, managed_roles):
125+
def test_team_team_read_role(rando, team, admin_user, post, setup_managed_roles):
90126
orgs = [Organization.objects.create(name=f'foo-{i}') for i in range(2)]
91127
teams = [Team.objects.create(name=f'foo-{i}', organization=orgs[i]) for i in range(2)]
92128
teams[1].member_role.members.add(rando)

awx/main/tests/functional/test_rbac_job_templates.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def test_system_admin_orphan_capabilities(self, job_template, admin_user):
165165

166166
@pytest.mark.django_db
167167
@pytest.mark.job_permissions
168-
def test_job_template_creator_access(project, organization, rando, post):
168+
def test_job_template_creator_access(project, organization, rando, post, setup_managed_roles):
169169
project.use_role.members.add(rando)
170170
response = post(
171171
url=reverse('api:job_template_list'),

awx/settings/defaults.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,13 +1148,8 @@
11481148

11491149
# Settings for the ansible_base RBAC system
11501150

1151-
# Only used internally, names of the managed RoleDefinitions to create
1152-
ANSIBLE_BASE_ROLE_PRECREATE = {
1153-
'object_admin': '{cls.__name__} Admin',
1154-
'org_admin': 'Organization Admin',
1155-
'org_children': 'Organization {cls.__name__} Admin',
1156-
'special': '{cls.__name__} {action}',
1157-
}
1151+
# This has been moved to data migration code
1152+
ANSIBLE_BASE_ROLE_PRECREATE = {}
11581153

11591154
# Name for auto-created roles that give users permissions to what they create
11601155
ANSIBLE_BASE_ROLE_CREATOR_NAME = '{cls.__name__} Creator'

0 commit comments

Comments
 (0)