mirror of
https://github.com/ansible/awx.git
synced 2026-03-23 11:55:04 -02:30
block user from shooting themselves in the foot by scheduling a manual project
This commit is contained in:
@@ -2826,6 +2826,8 @@ class ScheduleSerializer(BaseSerializer):
|
|||||||
def validate_unified_job_template(self, value):
|
def validate_unified_job_template(self, value):
|
||||||
if type(value) == InventorySource and value.source not in SCHEDULEABLE_PROVIDERS:
|
if type(value) == InventorySource and value.source not in SCHEDULEABLE_PROVIDERS:
|
||||||
raise serializers.ValidationError(_('Inventory Source must be a cloud resource.'))
|
raise serializers.ValidationError(_('Inventory Source must be a cloud resource.'))
|
||||||
|
elif type(value) == Project and value.scm_type == '':
|
||||||
|
raise serializers.ValidationError(_('Manual Project can not have a schedule set.'))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
# We reject rrules if:
|
# We reject rrules if:
|
||||||
|
|||||||
@@ -305,7 +305,8 @@ class BaseAccess(object):
|
|||||||
if display_method not in method_list:
|
if display_method not in method_list:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Actions not possible for reason unrelated to RBAC: validation, etc.
|
# Actions not possible for reason unrelated to RBAC
|
||||||
|
# Cannot copy with validation errors, or update a manual group/project
|
||||||
if display_method == 'copy' and isinstance(obj, JobTemplate):
|
if display_method == 'copy' and isinstance(obj, JobTemplate):
|
||||||
validation_errors, resources_needed_to_start = obj.resource_validation_data()
|
validation_errors, resources_needed_to_start = obj.resource_validation_data()
|
||||||
if validation_errors:
|
if validation_errors:
|
||||||
@@ -315,6 +316,10 @@ class BaseAccess(object):
|
|||||||
if obj.inventory_source and not obj.inventory_source._can_update():
|
if obj.inventory_source and not obj.inventory_source._can_update():
|
||||||
user_capabilities[display_method] = False
|
user_capabilities[display_method] = False
|
||||||
continue
|
continue
|
||||||
|
elif display_method in ['start', 'schedule'] and isinstance(obj, (Project)):
|
||||||
|
if obj.scm_type == '':
|
||||||
|
user_capabilities[display_method] = False
|
||||||
|
continue
|
||||||
|
|
||||||
# Grab the answer from the cache, if available
|
# Grab the answer from the cache, if available
|
||||||
if hasattr(obj, 'capabilities_cache') and display_method in obj.capabilities_cache:
|
if hasattr(obj, 'capabilities_cache') and display_method in obj.capabilities_cache:
|
||||||
@@ -341,10 +346,6 @@ class BaseAccess(object):
|
|||||||
elif display_method == 'copy' and isinstance(obj, (Group, Host)):
|
elif display_method == 'copy' and isinstance(obj, (Group, Host)):
|
||||||
user_capabilities['copy'] = user_capabilities['edit']
|
user_capabilities['copy'] = user_capabilities['edit']
|
||||||
continue
|
continue
|
||||||
elif display_method == 'start' and isinstance(obj, (Project)) and obj.scm_type == '':
|
|
||||||
# Special case to return False for a manual project
|
|
||||||
user_capabilities['start'] = False
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Preprocessing before the access method is called
|
# Preprocessing before the access method is called
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ def test_prefetch_jt_copy_capability(job_template, project, inventory, machine_c
|
|||||||
def test_manual_projects_no_update(project, get, admin_user):
|
def test_manual_projects_no_update(project, get, admin_user):
|
||||||
response = get(reverse('api:project_detail', args=[project.pk]), admin_user, expect=200)
|
response = get(reverse('api:project_detail', args=[project.pk]), admin_user, expect=200)
|
||||||
assert not response.data['summary_fields']['user_capabilities']['start']
|
assert not response.data['summary_fields']['user_capabilities']['start']
|
||||||
|
assert not response.data['summary_fields']['user_capabilities']['schedule']
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
@@ -136,3 +136,12 @@ def test_patch_project_null_organization(patch, organization, project, admin):
|
|||||||
@pytest.mark.django_db()
|
@pytest.mark.django_db()
|
||||||
def test_patch_project_null_organization_xfail(patch, project, org_admin):
|
def test_patch_project_null_organization_xfail(patch, project, org_admin):
|
||||||
patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': None}, org_admin, expect=400)
|
patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': None}, org_admin, expect=400)
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_cannot_schedule_manual_project(project, admin_user, post):
|
||||||
|
response = post(
|
||||||
|
reverse('api:project_schedules_list', args=(project.pk,)),
|
||||||
|
{"name": "foo", "description": "", "enabled": True,
|
||||||
|
"rrule": "DTSTART:20160926T040000Z RRULE:FREQ=HOURLY;INTERVAL=1",
|
||||||
|
"extra_data": {}}, admin_user, expect=400)
|
||||||
|
assert 'Manual' in response.data['unified_job_template'][0]
|
||||||
|
|||||||
Reference in New Issue
Block a user