Skip to content

Commit f881db3

Browse files
committed
Disable type creation and test unregistered model
1 parent 4d1c615 commit f881db3

File tree

5 files changed

+33
-27
lines changed

5 files changed

+33
-27
lines changed

ansible_base/rbac/management/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22

33
from django.apps import apps as global_apps
4-
from django.db import DEFAULT_DB_ALIAS, router, connection
4+
from django.db import DEFAULT_DB_ALIAS, connection, router
55

66
from ansible_base.rbac import permission_registry
77
from ansible_base.rbac.remote import get_resource_prefix
@@ -102,9 +102,12 @@ def sync_DAB_permissions(verbosity=2, using=DEFAULT_DB_ALIAS, apps=global_apps):
102102
table = DABContentType._meta.db_table
103103
pk_column = DABContentType._meta.pk.column
104104
with connection.cursor() as cursor:
105-
cursor.execute(f"""
105+
cursor.execute(
106+
f"""
106107
SELECT setval(
107108
pg_get_serial_sequence(%s, %s),
108109
(SELECT MAX({pk_column}) FROM {table})
109110
)
110-
""", [table, pk_column])
111+
""",
112+
[table, pk_column],
113+
)

ansible_base/rbac/models/content_type.py

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
import inspect
2-
import logging
32
from collections import defaultdict
43
from typing import Any, Dict, Optional, Sequence, Tuple, Type, Union
54

65
from django.apps import apps
7-
from django.db import connection
86
from django.db import models as django_models
97
from django.db.models.options import Options
108
from django.utils.translation import gettext_lazy as _
119

1210
from ..remote import RemoteObject, get_local_resource_prefix, get_resource_prefix
1311

14-
logger = logging.getLogger(__name__)
15-
1612

1713
class DABContentTypeManager(django_models.Manager["DABContentType"]):
1814
"""Manager storing DABContentType objects in a local cache like original ContentType.
@@ -76,12 +72,9 @@ def get_for_model(
7672
try:
7773
ct = self.get(service=service, app_label=opts.app_label, model=opts.model_name)
7874
except self.model.DoesNotExist:
79-
logger.warning(f'Could not find content type for {(service, opts.app_label, opts.model_name)}, so creating new')
80-
ct, _ = self.get_or_create(
81-
service=service,
82-
app_label=opts.app_label,
83-
model=opts.model_name,
84-
defaults=dict(api_slug=f'{service}.{opts.model_name}', pk_field_type=model._meta.pk.db_type(connection)),
75+
raise RuntimeError(
76+
f'Could not find content type for {(service, opts.app_label, opts.model_name)}, '
77+
'and creating new objects via get_for_model is not allowed for DAB RBAC'
8578
)
8679
self._add_to_cache(self.db, ct)
8780
return ct
@@ -135,19 +128,11 @@ def get_for_models(
135128
for model in opts_models:
136129
results[model] = ct
137130
self._add_to_cache(self.db, ct)
138-
# Named it service_create to not shadown variable from prior loop
139-
for (service_create, app_label, model_name), opts_models in needed_opts.items():
140-
if opts_models:
141-
pk_field_type = opts_models[0]._meta.pk.db_type(connection)
142-
else:
143-
pk_field_type = 'integer'
144-
logger.warning(f'Could not find content type for {(service_create, app_label, model_name)}, so creating new, out of:\n{needed_models.keys()}')
145-
ct = self.create(
146-
service=service_create, app_label=app_label, model=model_name, api_slug=f'{service_create}.{model_name}', pk_field_type=pk_field_type
131+
if needed_opts:
132+
raise RuntimeError(
133+
f'Could not find content type for any of {needed_opts.keys()}, '
134+
f'and creating new objects via get_for_models is not enabled for DAB RBAC, looked in:\n{needed_models.keys()}'
147135
)
148-
self._add_to_cache(self.db, ct)
149-
for model in opts_models:
150-
results[model] = ct
151136
return results
152137

153138
def get_by_natural_key(self, *args: str) -> "DABContentType":

ansible_base/rbac/models/role.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ def contribute_to_class(self, cls: Type[models.Model], name: str) -> None:
6969
self.managed = ManagedRoleManager(self.model._meta.apps)
7070

7171
def give_creator_permissions(self, user, obj) -> Optional['RoleUserAssignment']:
72+
if not permission_registry.is_registered(obj):
73+
return # Exit before getting content type, which will not exist
74+
7275
# If the user is a superuser, no need to bother giving the creator permissions
7376
for super_flag in settings.ANSIBLE_BASE_BYPASS_SUPERUSER_FLAGS:
7477
if getattr(user, super_flag):

test_app/tests/rbac/features/test_creator_permission.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import pytest
2+
from django.apps import apps
23
from django.test.utils import override_settings
34

4-
from ansible_base.rbac.models import DABContentType, RoleDefinition, RoleEvaluation
5+
from ansible_base.rbac.models import DABContentType, RoleDefinition, RoleEvaluation, RoleUserAssignment
56
from test_app.models import User
67

78
INVENTORY_OBJ_PERMS = ('change_inventory', 'update_inventory', 'view_inventory', 'delete_inventory')
@@ -60,3 +61,18 @@ def test_custom_creation_perms(rando, inventory):
6061
with override_settings(ANSIBLE_BASE_CREATOR_DEFAULTS=['change', 'view']):
6162
RoleDefinition.objects.give_creator_permissions(rando, inventory)
6263
assert set(perm_name.split('_', 1)[0] for perm_name in RoleEvaluation.get_permissions(rando, inventory)) == {'change', 'view'}
64+
65+
66+
@pytest.mark.django_db
67+
def test_creator_permission_for_unregistered_model(admin_api_client, inventory, inv_rd, user):
68+
prior_ct = DABContentType.objects.count()
69+
prior_assignments = RoleUserAssignment.objects.count()
70+
prior_rds = RoleDefinition.objects.count()
71+
72+
cls = apps.get_model('test_app.secretcolor')
73+
obj = cls.objects.create()
74+
RoleDefinition.objects.give_creator_permissions(user, obj) # should do nothing
75+
76+
assert DABContentType.objects.count() == prior_ct # did not create anything
77+
assert RoleUserAssignment.objects.count() == prior_assignments
78+
assert RoleDefinition.objects.count() == prior_rds

test_app/tests/rbac/remote/test_public_api_compat.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ def test_role_definition_list_remote_and_local(admin_api_client, inv_rd, foo_rd)
2020

2121

2222
@pytest.mark.django_db
23-
@pytest.mark.skip
2423
def test_create_remote_role_definition(admin_api_client, foo_type, foo_permission):
2524
"""
2625
Test creation of a custom, remote role definition.

0 commit comments

Comments
 (0)