1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 16:51:11 +03:00

Merge pull request #2919 from ryanpetrello/dispatcher-task-import-hardening

only allow the task dispatch worker to import and run decorated tasks

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
softwarefactory-project-zuul[bot] 2018-12-13 01:12:48 +00:00 committed by GitHub
commit 59df54b363
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 0 deletions

View File

@ -30,11 +30,18 @@ class TaskWorker(BaseWorker):
awx.main.tasks.delete_inventory
awx.main.tasks.RunProjectUpdate
'''
if not task.startswith('awx.'):
raise ValueError('{} is not a valid awx task'.format(task))
module, target = task.rsplit('.', 1)
module = importlib.import_module(module)
_call = None
if hasattr(module, target):
_call = getattr(module, target, None)
if not (
hasattr(_call, 'apply_async') and hasattr(_call, 'delay')
):
raise ValueError('{} is not decorated with @task()'.format(task))
return _call
def run_callable(self, body):
@ -78,6 +85,7 @@ class TaskWorker(BaseWorker):
try:
result = self.run_callable(body)
except Exception as exc:
result = exc
try:
if getattr(exc, 'is_awx_task_error', False):

View File

@ -14,6 +14,10 @@ from awx.main.dispatch.publish import task
from awx.main.dispatch.worker import BaseWorker, TaskWorker
def restricted(a, b):
raise AssertionError("This code should not run because it isn't decorated with @task")
@task()
def add(a, b):
return a + b
@ -25,6 +29,11 @@ class BaseTask(object):
return add(a, b)
class Restricted(object):
def run(self, a, b):
raise AssertionError("This code should not run because it isn't decorated with @task")
@task()
class Adder(BaseTask):
def run(self, a, b):
@ -262,6 +271,14 @@ class TestTaskDispatcher:
})
assert result == 4
def test_function_dispatch_must_be_decorated(self):
result = self.tm.perform_work({
'task': 'awx.main.tests.functional.test_dispatch.restricted',
'args': [2, 2]
})
assert isinstance(result, ValueError)
assert result.message == 'awx.main.tests.functional.test_dispatch.restricted is not decorated with @task()' # noqa
def test_method_dispatch(self):
result = self.tm.perform_work({
'task': 'awx.main.tests.functional.test_dispatch.Adder',
@ -269,6 +286,29 @@ class TestTaskDispatcher:
})
assert result == 4
def test_method_dispatch_must_be_decorated(self):
result = self.tm.perform_work({
'task': 'awx.main.tests.functional.test_dispatch.Restricted',
'args': [2, 2]
})
assert isinstance(result, ValueError)
assert result.message == 'awx.main.tests.functional.test_dispatch.Restricted is not decorated with @task()' # noqa
def test_python_function_cannot_be_imported(self):
result = self.tm.perform_work({
'task': 'os.system',
'args': ['ls'],
})
assert isinstance(result, ValueError)
assert result.message == 'os.system is not a valid awx task' # noqa
def test_undefined_function_cannot_be_imported(self):
result = self.tm.perform_work({
'task': 'awx.foo.bar'
})
assert isinstance(result, ImportError)
assert result.message == 'No module named foo' # noqa
class TestTaskPublisher: