mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 18:40:01 -03:30
inject WF node prompts into new jobs, new workflow RBAC tests
This commit is contained in:
parent
2ffa7a91ec
commit
9acd50b8f3
@ -2631,10 +2631,6 @@ class WorkflowJobTemplateNodeList(ListCreateAPIView):
|
||||
serializer_class = WorkflowJobTemplateNodeListSerializer
|
||||
new_in_310 = True
|
||||
|
||||
def update_raw_data(self, data):
|
||||
for fd in ['job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags']:
|
||||
data[fd] = None
|
||||
return super(WorkflowJobTemplateNodeList, self).update_raw_data(data)
|
||||
|
||||
class WorkflowJobTemplateNodeDetail(RetrieveUpdateDestroyAPIView):
|
||||
|
||||
|
||||
@ -1132,10 +1132,26 @@ class SystemJobAccess(BaseAccess):
|
||||
'''
|
||||
model = SystemJob
|
||||
|
||||
# TODO:
|
||||
class WorkflowJobTemplateNodeAccess(BaseAccess):
|
||||
'''
|
||||
I can see/use a WorkflowJobTemplateNode if I have permission to associated Workflow Job Template
|
||||
I can see/use a WorkflowJobTemplateNode if I have read permission
|
||||
to associated Workflow Job Template
|
||||
|
||||
In order to add a node, I need:
|
||||
- admin access to parent WFJT
|
||||
- execute access to the unified job template being used
|
||||
- access to any credential or inventory provided as the prompted fields
|
||||
|
||||
In order to do anything to a node, I need admin access to its WFJT
|
||||
|
||||
In order to edit fields on a node, I need:
|
||||
- execute access to the unified job template of the node
|
||||
- access to BOTH credential and inventory post-change, if present
|
||||
|
||||
In order to delete a node, I only need the admin access its WFJT
|
||||
|
||||
In order to manage connections (edges) between nodes I do not need anything
|
||||
beyond the standard admin access to its WFJT
|
||||
'''
|
||||
model = WorkflowJobTemplateNode
|
||||
|
||||
@ -1148,26 +1164,78 @@ class WorkflowJobTemplateNodeAccess(BaseAccess):
|
||||
self.user, 'read_role'))
|
||||
return qs
|
||||
|
||||
@check_superuser
|
||||
def can_read(self, obj):
|
||||
def can_use_prompted_resources(self, data):
|
||||
cred_pk = data.get('credential', None)
|
||||
inv_pk = data.get('inventory', None)
|
||||
if cred_pk:
|
||||
credential = get_object_or_400(Credential, pk=cred_pk)
|
||||
if self.user not in credential.use_role:
|
||||
return False
|
||||
if inv_pk:
|
||||
inventory = get_object_or_400(Inventory, pk=inv_pk)
|
||||
if self.user not in inventory.use_role:
|
||||
return False
|
||||
return True
|
||||
|
||||
@check_superuser
|
||||
def can_add(self, data):
|
||||
if not data: # So the browseable API will work
|
||||
return True
|
||||
|
||||
wfjt_pk = data.get('workflow_job_template', None)
|
||||
if wfjt_pk:
|
||||
wfjt = get_object_or_400(WorkflowJobTemplate, pk=wfjt_pk)
|
||||
if self.user not in wfjt.admin_role:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
if not self.can_use_prompted_resources(data):
|
||||
return False
|
||||
return True
|
||||
|
||||
@check_superuser
|
||||
def wfjt_admin(self, obj):
|
||||
if not obj.workflow_job_template:
|
||||
return self.user.is_superuser
|
||||
else:
|
||||
return self.user in obj.workflow_job_template.admin_role
|
||||
|
||||
def ujt_execute(self, obj):
|
||||
if not obj.unified_job_template:
|
||||
return self.wfjt_admin(obj)
|
||||
else:
|
||||
return self.user in obj.unified_job_template.execute_role and self.wfjt_admin(obj)
|
||||
|
||||
def can_change(self, obj, data):
|
||||
if self.can_add(data) is False:
|
||||
if not data:
|
||||
return True
|
||||
|
||||
if not self.ujt_execute(obj):
|
||||
# should not be able to edit the prompts if lacking access to UJT
|
||||
return False
|
||||
|
||||
if 'credential' in data or 'inventory' in data:
|
||||
new_data = data
|
||||
if 'credential' not in data:
|
||||
new_data['credential'] = self.credential
|
||||
if 'inventory' not in data:
|
||||
new_data['inventory'] = self.inventory
|
||||
return self.can_use_prompted_resources(new_data)
|
||||
return True
|
||||
|
||||
def can_delete(self, obj):
|
||||
return self.can_change(obj, None)
|
||||
return self.wfjt_admin(obj)
|
||||
|
||||
def check_same_WFJT(self, obj, sub_obj):
|
||||
if type(obj) != self.model or type(sub_obj) != self.model:
|
||||
raise Exception('Attaching workflow nodes only allowed for other nodes')
|
||||
if obj.workflow_job_template != sub_obj.workflow_job_template:
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_attach(self, obj, sub_obj, relationship, data, skip_sub_obj_read_check=False):
|
||||
return self.wfjt_admin(obj) and self.check_same_WFJT(obj, sub_obj)
|
||||
|
||||
def can_unattach(self, obj, sub_obj, relationship, data, skip_sub_obj_read_check=False):
|
||||
return self.wfjt_admin(obj) and self.check_same_WFJT(obj, sub_obj)
|
||||
|
||||
class WorkflowJobNodeAccess(BaseAccess):
|
||||
'''
|
||||
@ -1199,7 +1267,7 @@ class WorkflowJobNodeAccess(BaseAccess):
|
||||
def can_delete(self, obj):
|
||||
return False
|
||||
|
||||
# TODO:
|
||||
# TODO: revisit for survey logic, notification attachments?
|
||||
class WorkflowJobTemplateAccess(BaseAccess):
|
||||
'''
|
||||
I can only see/manage Workflow Job Templates if I'm a super user
|
||||
@ -1293,7 +1361,7 @@ class WorkflowJobTemplateAccess(BaseAccess):
|
||||
if ('organization' not in data or
|
||||
(org_pk is None and obj.organization is None) or
|
||||
(obj.organization and obj.organization.pk == org_pk)):
|
||||
# The simple case
|
||||
# No organization changes
|
||||
return self.user in obj.admin_role
|
||||
|
||||
# If it already has an organization set, must be admin of the org to change it
|
||||
@ -1314,11 +1382,13 @@ class WorkflowJobTemplateAccess(BaseAccess):
|
||||
return True
|
||||
|
||||
|
||||
|
||||
class WorkflowJobAccess(BaseAccess):
|
||||
'''
|
||||
I can only see Workflow Jobs if I can see the associated
|
||||
workflow job template that it was created from.
|
||||
I can delete them if I am admin of their workflow job template
|
||||
I can cancel one if I can delete it
|
||||
I can also cancel it if I started it
|
||||
'''
|
||||
model = WorkflowJob
|
||||
|
||||
@ -1345,6 +1415,10 @@ class WorkflowJobAccess(BaseAccess):
|
||||
return self.user.is_superuser
|
||||
return self.user in obj.workflow_job_template.admin_role
|
||||
|
||||
def can_cancel(self, obj):
|
||||
if not obj.can_cancel:
|
||||
return False
|
||||
return self.can_delete(obj) or self.user == obj.created_by
|
||||
|
||||
class AdHocCommandAccess(BaseAccess):
|
||||
'''
|
||||
|
||||
@ -260,9 +260,7 @@ def do_spawn_workflow_jobs():
|
||||
dag = WorkflowDAG(workflow_job)
|
||||
spawn_nodes = dag.bfs_nodes_to_run()
|
||||
for spawn_node in spawn_nodes:
|
||||
# TODO: Inject job template template params as kwargs.
|
||||
# Make sure to take into account extra_vars merge logic
|
||||
kv = {}
|
||||
kv = spawn_node.get_job_kwargs()
|
||||
job = spawn_node.unified_job_template.create_unified_job(**kv)
|
||||
spawn_node.job = job
|
||||
spawn_node.save()
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import jsonfield.fields
|
||||
import awx.main.models.notifications
|
||||
import django.db.models.deletion
|
||||
import awx.main.models.workflow
|
||||
@ -101,4 +102,70 @@ class Migration(migrations.Migration):
|
||||
name='workflow_job_template_node',
|
||||
field=models.ManyToManyField(to='main.WorkflowJobTemplateNode', blank=True),
|
||||
),
|
||||
# RBAC, prompting changes
|
||||
migrations.AddField(
|
||||
model_name='workflowjobnode',
|
||||
name='char_prompts',
|
||||
field=jsonfield.fields.JSONField(default={}, blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobnode',
|
||||
name='credential',
|
||||
field=models.ForeignKey(related_name='workflowjobnodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobnode',
|
||||
name='inventory',
|
||||
field=models.ForeignKey(related_name='workflowjobnodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Inventory', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='organization',
|
||||
field=models.ForeignKey(related_name='workflows', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='main.Organization', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'organization.auditor_role', b'execute_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='char_prompts',
|
||||
field=jsonfield.fields.JSONField(default={}, blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='credential',
|
||||
field=models.ForeignKey(related_name='workflowjobtemplatenodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='inventory',
|
||||
field=models.ForeignKey(related_name='workflowjobtemplatenodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Inventory', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobnode',
|
||||
name='unified_job_template',
|
||||
field=models.ForeignKey(related_name='workflowjobnodes', on_delete=django.db.models.deletion.SET_NULL, default=None, to='main.UnifiedJobTemplate', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobnode',
|
||||
name='workflow_job',
|
||||
field=models.ForeignKey(related_name='workflow_job_nodes', default=None, blank=True, to='main.WorkflowJob', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_administrator', b'organization.admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='unified_job_template',
|
||||
field=models.ForeignKey(related_name='workflowjobtemplatenodes', on_delete=django.db.models.deletion.SET_NULL, default=None, to='main.UnifiedJobTemplate', null=True),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import jsonfield.fields
|
||||
import django.db.models.deletion
|
||||
import awx.main.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0035_v310_jobevent_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='workflowjobnode',
|
||||
name='char_prompts',
|
||||
field=jsonfield.fields.JSONField(default={}, blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobnode',
|
||||
name='credential',
|
||||
field=models.ForeignKey(related_name='workflowjobnodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobnode',
|
||||
name='inventory',
|
||||
field=models.ForeignKey(related_name='workflowjobnodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Inventory', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='organization',
|
||||
field=models.ForeignKey(related_name='workflows', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='main.Organization', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'organization.auditor_role', b'execute_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='char_prompts',
|
||||
field=jsonfield.fields.JSONField(default={}, blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='credential',
|
||||
field=models.ForeignKey(related_name='workflowjobtemplatenodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='inventory',
|
||||
field=models.ForeignKey(related_name='workflowjobtemplatenodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Inventory', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobnode',
|
||||
name='unified_job_template',
|
||||
field=models.ForeignKey(related_name='workflowjobnodes', on_delete=django.db.models.deletion.SET_NULL, default=None, to='main.UnifiedJobTemplate', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobnode',
|
||||
name='workflow_job',
|
||||
field=models.ForeignKey(related_name='workflow_job_nodes', default=None, blank=True, to='main.WorkflowJob', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobtemplate',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_administrator', b'organization.admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='workflowjobtemplatenode',
|
||||
name='unified_job_template',
|
||||
field=models.ForeignKey(related_name='workflowjobtemplatenodes', on_delete=django.db.models.deletion.SET_NULL, default=None, to='main.UnifiedJobTemplate', null=True),
|
||||
),
|
||||
]
|
||||
@ -22,6 +22,9 @@ from awx.main.models.rbac import (
|
||||
from awx.main.fields import ImplicitRoleField
|
||||
from awx.main.models.mixins import ResourceMixin
|
||||
|
||||
import yaml
|
||||
import json
|
||||
|
||||
__all__ = ['WorkflowJobTemplate', 'WorkflowJob', 'WorkflowJobOptions', 'WorkflowJobNode', 'WorkflowJobTemplateNode',]
|
||||
|
||||
CHAR_PROMPTS_LIST = ['job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags']
|
||||
@ -150,6 +153,33 @@ class WorkflowJobNode(WorkflowNodeBase):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:workflow_job_node_detail', args=(self.pk,))
|
||||
|
||||
def get_job_kwargs(self):
|
||||
data = {}
|
||||
# rejecting/accepting prompting variables done with the node copy
|
||||
if self.inventory:
|
||||
data['inventory'] = self.inventory
|
||||
if self.credential:
|
||||
data['credential'] = self.credential
|
||||
if self.char_prompts:
|
||||
data.update(self.char_prompts)
|
||||
# process extra_vars
|
||||
extra_vars = {}
|
||||
if self.workflow_job and self.workflow_job.extra_vars:
|
||||
try:
|
||||
WJ_json_extra_vars = json.loads(
|
||||
(self.workflow_job.extra_vars or '').strip() or '{}')
|
||||
except ValueError:
|
||||
try:
|
||||
WJ_json_extra_vars = yaml.safe_load(self.workflow_job.extra_vars)
|
||||
except yaml.YAMLError:
|
||||
WJ_json_extra_vars = {}
|
||||
extra_vars.update(WJ_json_extra_vars)
|
||||
# TODO: merge artifacts, add ancestor_artifacts to kwargs
|
||||
if extra_vars:
|
||||
data['extra_vars'] = extra_vars
|
||||
print ' job KV data: ' + str(data)
|
||||
return data
|
||||
|
||||
class WorkflowJobOptions(BaseModel):
|
||||
class Meta:
|
||||
abstract = True
|
||||
@ -164,9 +194,6 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, ResourceMixin)
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
|
||||
# admin_role = ImplicitRoleField(
|
||||
# parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
# )
|
||||
organization = models.ForeignKey(
|
||||
'Organization',
|
||||
blank=True,
|
||||
|
||||
@ -167,11 +167,11 @@ def mk_workflow_job(status='new', workflow_job_template=None, extra_vars={},
|
||||
job.save()
|
||||
return job
|
||||
|
||||
def mk_workflow_job_template(name, extra_vars='', spec=None, persisted=True):
|
||||
def mk_workflow_job_template(name, extra_vars='', spec=None, organization=None, persisted=True):
|
||||
if extra_vars:
|
||||
extra_vars = json.dumps(extra_vars)
|
||||
|
||||
wfjt = WorkflowJobTemplate(name=name, extra_vars=extra_vars)
|
||||
wfjt = WorkflowJobTemplate(name=name, extra_vars=extra_vars, organization=organization)
|
||||
|
||||
wfjt.survey_spec = spec
|
||||
if wfjt.survey_spec is not None:
|
||||
|
||||
@ -360,16 +360,20 @@ def generate_workflow_job_template_nodes(workflow_job_template,
|
||||
new_node = WorkflowJobTemplateNode(workflow_job_template=workflow_job_template,
|
||||
unified_job_template=node['unified_job_template'],
|
||||
id=i)
|
||||
if persisted:
|
||||
new_node.save()
|
||||
new_nodes.append(new_node)
|
||||
|
||||
node_types = ['success_nodes', 'failure_nodes', 'always_nodes']
|
||||
for node_type in node_types:
|
||||
for i, new_node in enumerate(new_nodes):
|
||||
if node_type not in workflow_job_template_nodes[i]:
|
||||
continue
|
||||
for related_index in workflow_job_template_nodes[i][node_type]:
|
||||
getattr(new_node, node_type).add(new_nodes[related_index])
|
||||
|
||||
# TODO: Implement survey and jobs
|
||||
def create_workflow_job_template(name, persisted=True, **kwargs):
|
||||
def create_workflow_job_template(name, organization=None, persisted=True, **kwargs):
|
||||
Objects = generate_objects(["workflow_job_template",
|
||||
"workflow_job_template_nodes",
|
||||
"survey",], kwargs)
|
||||
@ -382,7 +386,8 @@ def create_workflow_job_template(name, persisted=True, **kwargs):
|
||||
if 'survey' in kwargs:
|
||||
spec = create_survey_spec(kwargs['survey'])
|
||||
|
||||
wfjt = mk_workflow_job_template(name,
|
||||
wfjt = mk_workflow_job_template(name,
|
||||
organization=organization,
|
||||
spec=spec,
|
||||
extra_vars=extra_vars,
|
||||
persisted=persisted)
|
||||
|
||||
73
awx/main/tests/functional/test_rbac_workflow.py
Normal file
73
awx/main/tests/functional/test_rbac_workflow.py
Normal file
@ -0,0 +1,73 @@
|
||||
import pytest
|
||||
|
||||
from awx.main.access import (
|
||||
WorkflowJobTemplateAccess,
|
||||
WorkflowJobTemplateNodeAccess,
|
||||
WorkflowJobAccess,
|
||||
# WorkflowJobNodeAccess
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt(workflow_job_template_factory, organization):
|
||||
objects = workflow_job_template_factory('test_workflow', organization=organization, persisted=True)
|
||||
return objects.workflow_job_template
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt_with_nodes(workflow_job_template_factory, organization, job_template):
|
||||
objects = workflow_job_template_factory(
|
||||
'test_workflow', organization=organization, workflow_job_template_nodes=[{'unified_job_template': job_template}], persisted=True)
|
||||
return objects.workflow_job_template
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt_node(wfjt_with_nodes):
|
||||
return wfjt_with_nodes.workflow_job_template_nodes.all()[0]
|
||||
|
||||
@pytest.fixture
|
||||
def workflow_job(wfjt):
|
||||
return wfjt.jobs.create(name='test_workflow')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestWorkflowJobTemplateAccess:
|
||||
|
||||
def test_random_user_no_edit(self, wfjt, rando):
|
||||
access = WorkflowJobTemplateAccess(rando)
|
||||
assert not access.can_change(wfjt, {'name': 'new name'})
|
||||
|
||||
def test_org_admin_edit(self, wfjt, org_admin):
|
||||
access = WorkflowJobTemplateAccess(org_admin)
|
||||
assert access.can_change(wfjt, {'name': 'new name'})
|
||||
|
||||
def test_org_admin_role_inheritance(self, wfjt, org_admin):
|
||||
assert org_admin in wfjt.admin_role
|
||||
assert org_admin in wfjt.execute_role
|
||||
assert org_admin in wfjt.read_role
|
||||
|
||||
def test_jt_blocks_copy(self, wfjt_with_nodes, org_admin):
|
||||
"""I want to copy a workflow JT in my organization, but someone
|
||||
included a job template that I don't have access to, so I can
|
||||
not copy the WFJT as-is"""
|
||||
access = WorkflowJobTemplateAccess(org_admin)
|
||||
assert not access.can_add({'reference_obj': wfjt_with_nodes})
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestWorkflowJobTemplateNodeAccess:
|
||||
|
||||
def test_jt_access_to_edit(self, wfjt_node, org_admin):
|
||||
access = WorkflowJobTemplateNodeAccess(org_admin)
|
||||
assert not access.can_change(wfjt_node, {'job_type': 'scan'})
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestWorkflowJobAccess:
|
||||
|
||||
def test_wfjt_admin_delete(self, wfjt, workflow_job, rando):
|
||||
wfjt.admin_role.members.add(rando)
|
||||
access = WorkflowJobAccess(rando)
|
||||
assert access.can_delete(workflow_job)
|
||||
|
||||
def test_cancel_your_own_job(self, wfjt, workflow_job, rando):
|
||||
wfjt.execute_role.members.add(rando)
|
||||
workflow_job.created_by = rando
|
||||
workflow_job.save()
|
||||
access = WorkflowJobAccess(rando)
|
||||
assert access.can_cancel(workflow_job)
|
||||
@ -118,11 +118,19 @@ class TestWorkflowAccessMethods:
|
||||
objects = workflow_job_template_factory('test_workflow', persisted=False)
|
||||
return objects.workflow_job_template
|
||||
|
||||
class MockQuerySet(object):
|
||||
pass
|
||||
|
||||
def test_workflow_can_add(self, workflow, user_unit):
|
||||
# user_unit.admin_of_organizations = self.MockQuerySet()
|
||||
access = WorkflowJobTemplateAccess(user_unit)
|
||||
assert access.can_add({'organization': 1})
|
||||
organization = Organization(name='test-org')
|
||||
workflow.organization = organization
|
||||
organization.admin_role = Role()
|
||||
|
||||
def mock_get_object(Class, **kwargs):
|
||||
if Class == Organization:
|
||||
return organization
|
||||
else:
|
||||
raise Exception('Item requested has not been mocked')
|
||||
|
||||
access = WorkflowJobTemplateAccess(user_unit)
|
||||
with mock.patch('awx.main.models.rbac.Role.__contains__', return_value=True):
|
||||
with mock.patch('awx.main.access.get_object_or_400', mock_get_object):
|
||||
assert access.can_add({'organization': 1})
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user