Merge "Fix plugin injection vulnerability"
This commit is contained in:
commit
18ded8798d
|
@ -0,0 +1,17 @@
|
|||
- pipeline:
|
||||
name: check
|
||||
manager: independent
|
||||
post-review: true
|
||||
trigger:
|
||||
gerrit:
|
||||
- event: patchset-created
|
||||
success:
|
||||
gerrit:
|
||||
Verified: 1
|
||||
failure:
|
||||
gerrit:
|
||||
Verified: -1
|
||||
|
||||
- job:
|
||||
name: base
|
||||
parent: null
|
|
@ -0,0 +1 @@
|
|||
test
|
|
@ -0,0 +1,14 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def my_cool_test(string):
|
||||
shell_output = subprocess.check_output(['hostname'])
|
||||
return 'hostname: %s' % shell_output.decode('utf-8')
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'my_cool_test': my_cool_test
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
- name: Test filter plugin
|
||||
debug:
|
||||
msg: "{{ 'ignore me' | my_cool_test }}"
|
|
@ -0,0 +1,4 @@
|
|||
- hosts: all
|
||||
roles:
|
||||
- bare-role
|
||||
|
|
@ -0,0 +1 @@
|
|||
symlink: ../filter-plugin-playbook/filter_plugins
|
|
@ -0,0 +1,5 @@
|
|||
- hosts: all
|
||||
tasks:
|
||||
- name: Test filter plugin
|
||||
debug:
|
||||
msg: "{{ 'ignore me' | my_cool_test }}"
|
|
@ -0,0 +1,14 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def my_cool_test(string):
|
||||
shell_output = subprocess.check_output(['hostname'])
|
||||
return 'hostname: %s' % shell_output.decode('utf-8')
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'my_cool_test': my_cool_test
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
- hosts: all
|
||||
tasks:
|
||||
- name: Test filter plugin
|
||||
debug:
|
||||
msg: "{{ 'ignore me' | my_cool_test }}"
|
|
@ -0,0 +1,14 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def my_cool_test(string):
|
||||
shell_output = subprocess.check_output(['hostname'])
|
||||
return 'hostname: %s' % shell_output.decode('utf-8')
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'my_cool_test': my_cool_test
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
- name: Test filter plugin
|
||||
debug:
|
||||
msg: "{{ 'ignore me' | my_cool_test }}"
|
|
@ -0,0 +1,4 @@
|
|||
- hosts: all
|
||||
roles:
|
||||
- local-role
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
- hosts: all
|
||||
roles:
|
||||
- shared-bare-role
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
- hosts: all
|
||||
roles:
|
||||
- shared-role
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
- project:
|
||||
check:
|
||||
jobs:
|
||||
- noop
|
|
@ -0,0 +1,14 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def my_cool_test(string):
|
||||
shell_output = subprocess.check_output(['hostname'])
|
||||
return 'hostname: %s' % shell_output.decode('utf-8')
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'my_cool_test': my_cool_test
|
||||
}
|
3
tests/fixtures/config/speculative-plugins/git/org_project2/roles/shared-role/tasks/main.yaml
vendored
Normal file
3
tests/fixtures/config/speculative-plugins/git/org_project2/roles/shared-role/tasks/main.yaml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
- name: Test filter plugin
|
||||
debug:
|
||||
msg: "{{ 'ignore me' | my_cool_test }}"
|
14
tests/fixtures/config/speculative-plugins/git/org_project3/filter_plugins/main.py
vendored
Normal file
14
tests/fixtures/config/speculative-plugins/git/org_project3/filter_plugins/main.py
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def my_cool_test(string):
|
||||
shell_output = subprocess.check_output(['hostname'])
|
||||
return 'hostname: %s' % shell_output.decode('utf-8')
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'my_cool_test': my_cool_test
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
- name: Test filter plugin
|
||||
debug:
|
||||
msg: "{{ 'ignore me' | my_cool_test }}"
|
|
@ -0,0 +1,4 @@
|
|||
- hosts: all
|
||||
roles:
|
||||
- project-role
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def my_cool_test(string):
|
||||
shell_output = subprocess.check_output(['hostname'])
|
||||
return 'hostname: %s' % shell_output.decode('utf-8')
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'my_cool_test': my_cool_test
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
- name: Test filter plugin
|
||||
debug:
|
||||
msg: "{{ 'ignore me' | my_cool_test }}"
|
|
@ -0,0 +1,11 @@
|
|||
- tenant:
|
||||
name: tenant-one
|
||||
source:
|
||||
gerrit:
|
||||
config-projects:
|
||||
- common-config
|
||||
untrusted-projects:
|
||||
- org/project
|
||||
- org/project2
|
||||
- org/project3
|
||||
- org/projectrole
|
|
@ -3429,3 +3429,48 @@ class TestJobOutput(AnsibleZuulTestCase):
|
|||
log_output = output.getvalue()
|
||||
self.assertIn('Final playbook failed', log_output)
|
||||
self.assertIn('Failure test', log_output)
|
||||
|
||||
|
||||
class TestPlugins(AnsibleZuulTestCase):
|
||||
tenant_config_file = 'config/speculative-plugins/main.yaml'
|
||||
|
||||
def _run_job(self, job_name, project='org/project', roles=''):
|
||||
# Output extra ansible info so we might see errors.
|
||||
self.executor_server.verbose = True
|
||||
conf = textwrap.dedent(
|
||||
"""
|
||||
- job:
|
||||
name: {job_name}
|
||||
run: playbooks/{job_name}/test.yaml
|
||||
nodeset:
|
||||
nodes:
|
||||
- name: controller
|
||||
label: whatever
|
||||
{roles}
|
||||
- project:
|
||||
check:
|
||||
jobs:
|
||||
- {job_name}
|
||||
""".format(job_name=job_name, roles=roles))
|
||||
|
||||
file_dict = {'zuul.yaml': conf}
|
||||
A = self.fake_gerrit.addFakeChange(project, 'master', 'A',
|
||||
files=file_dict)
|
||||
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
|
||||
self.waitUntilSettled()
|
||||
|
||||
message = A.messages[0]
|
||||
self.assertIn('ERROR Ansible plugin dir', message)
|
||||
self.assertIn('found adjacent to playbook', message)
|
||||
self.assertIn('in non-trusted repo', message)
|
||||
|
||||
def test_filter_plugin(self):
|
||||
self._run_job('filter-plugin-playbook')
|
||||
self._run_job('filter-plugin-playbook-symlink')
|
||||
self._run_job('filter-plugin-bare-role')
|
||||
self._run_job('filter-plugin-role')
|
||||
self._run_job('filter-plugin-repo-role', project='org/projectrole')
|
||||
self._run_job('filter-plugin-shared-role',
|
||||
roles="roles: [{zuul: 'org/project2'}]")
|
||||
self._run_job('filter-plugin-shared-bare-role',
|
||||
roles="roles: [{zuul: 'org/project3', name: 'shared'}]")
|
||||
|
|
|
@ -1028,6 +1028,7 @@ class AnsibleJob(object):
|
|||
|
||||
'''
|
||||
for entry in os.listdir(path):
|
||||
entry = os.path.join(path, entry)
|
||||
if os.path.isdir(entry) and entry.endswith('_plugins'):
|
||||
raise ExecutorError(
|
||||
"Ansible plugin dir %s found adjacent to playbook %s in "
|
||||
|
@ -1036,8 +1037,40 @@ class AnsibleJob(object):
|
|||
def findPlaybook(self, path, trusted=False):
|
||||
if os.path.exists(path):
|
||||
if not trusted:
|
||||
# Plugins can be defined in multiple locations within the
|
||||
# playbook's subtree.
|
||||
#
|
||||
# 1. directly within the playbook:
|
||||
# block playbook_dir/*_plugins
|
||||
#
|
||||
# 2. within a role defined in playbook_dir/<rolename>:
|
||||
# block playbook_dir/*/*_plugins
|
||||
#
|
||||
# 3. within a role defined in playbook_dir/roles/<rolename>:
|
||||
# block playbook_dir/roles/*/*_plugins
|
||||
|
||||
playbook_dir = os.path.dirname(os.path.abspath(path))
|
||||
self._blockPluginDirs(playbook_dir)
|
||||
paths_to_check = []
|
||||
|
||||
def addPathsToCheck(root_dir):
|
||||
if os.path.isdir(root_dir):
|
||||
for entry in os.listdir(root_dir):
|
||||
entry = os.path.join(root_dir, entry)
|
||||
if os.path.isdir(entry):
|
||||
paths_to_check.append(entry)
|
||||
|
||||
# handle case 1
|
||||
paths_to_check.append(playbook_dir)
|
||||
|
||||
# handle case 2
|
||||
addPathsToCheck(playbook_dir)
|
||||
|
||||
# handle case 3
|
||||
addPathsToCheck(os.path.join(playbook_dir, 'roles'))
|
||||
|
||||
for path_to_check in paths_to_check:
|
||||
self._blockPluginDirs(path_to_check)
|
||||
|
||||
return path
|
||||
raise ExecutorError("Unable to find playbook %s" % path)
|
||||
|
||||
|
|
Loading…
Reference in New Issue