Add 'allow-secrets' pipeline attribute
This permits an operator to specify that a given pipeline should
never run a job with secrets. This may be used, for example, to
ensure that no one adds, say, the pypi-upload job to a check
pipeline and then uses that to expose credentials.
Change-Id: I606a76fe9ed19bb87d78f07195fb3950805e8726
diff --git a/tests/fixtures/config/ansible/git/common-config/zuul.yaml b/tests/fixtures/config/ansible/git/common-config/zuul.yaml
index 3678f94..6d829e4 100644
--- a/tests/fixtures/config/ansible/git/common-config/zuul.yaml
+++ b/tests/fixtures/config/ansible/git/common-config/zuul.yaml
@@ -2,6 +2,7 @@
name: check
manager: independent
source: gerrit
+ allow-secrets: true
trigger:
gerrit:
- event: patchset-created
diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py
index fc2757c..f906095 100644
--- a/tests/unit/test_model.py
+++ b/tests/unit/test_model.py
@@ -616,6 +616,43 @@
"Project project2 is not allowed to run job job"):
item.freezeJobGraph()
+ def test_job_pipeline_allow_secrets(self):
+ self.pipeline.allow_secrets = False
+ job = configloader.JobParser.fromYaml(self.tenant, self.layout, {
+ '_source_context': self.context,
+ '_start_mark': self.start_mark,
+ 'name': 'job',
+ })
+ auth = model.AuthContext()
+ auth.secrets.append('foo')
+ job.auth = auth
+
+ self.layout.addJob(job)
+
+ project_config = configloader.ProjectParser.fromYaml(
+ self.tenant, self.layout, [{
+ '_source_context': self.context,
+ '_start_mark': self.start_mark,
+ 'name': 'project',
+ 'gate': {
+ 'jobs': [
+ 'job'
+ ]
+ }
+ }]
+ )
+ self.layout.addProjectConfig(project_config)
+
+ change = model.Change(self.project)
+ # Test master
+ change.branch = 'master'
+ item = self.queue.enqueueChange(change)
+ item.current_build_set.layout = self.layout
+ with testtools.ExpectedException(
+ Exception,
+ "Pipeline gate does not allow jobs with secrets"):
+ item.freezeJobGraph()
+
class TestJobTimeData(BaseTestCase):
def setUp(self):
diff --git a/zuul/configloader.py b/zuul/configloader.py
index 21f0f64..64c8db4 100644
--- a/zuul/configloader.py
+++ b/zuul/configloader.py
@@ -608,6 +608,7 @@
'footer-message': str,
'dequeue-on-new-patchset': bool,
'ignore-dependencies': bool,
+ 'allow-secrets': bool,
'disable-after-consecutive-failures':
vs.All(int, vs.Range(min=1)),
'window': window,
@@ -655,6 +656,7 @@
'dequeue-on-new-patchset', True)
pipeline.ignore_dependencies = conf.get(
'ignore-dependencies', False)
+ pipeline.allow_secrets = conf.get('allow-secrets', False)
for conf_key, action in PipelineParser.reporter_actions.items():
reporter_set = []
diff --git a/zuul/model.py b/zuul/model.py
index 846463b..cd63a94 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -121,6 +121,7 @@
self.success_message = None
self.footer_message = None
self.start_message = None
+ self.allow_secrets = False
self.dequeue_on_new_patchset = True
self.ignore_dependencies = False
self.manager = None
@@ -2321,7 +2322,9 @@
def addProjectConfig(self, project_config):
self.project_configs[project_config.name] = project_config
- def _createJobGraph(self, change, job_list, job_graph):
+ def _createJobGraph(self, item, job_list, job_graph):
+ change = item.change
+ pipeline = item.pipeline
for jobname in job_list.jobs:
# This is the final job we are constructing
frozen_job = None
@@ -2360,6 +2363,11 @@
change.project.name not in frozen_job.allowed_projects):
raise Exception("Project %s is not allowed to run job %s" %
(change.project.name, frozen_job.name))
+ if ((not pipeline.allow_secrets) and frozen_job.auth and
+ frozen_job.auth.secrets):
+ raise Exception("Pipeline %s does not allow jobs with "
+ "secrets (job %s)" % (
+ pipeline.name, frozen_job.name))
job_graph.addJob(frozen_job)
def createJobGraph(self, item):
@@ -2371,7 +2379,7 @@
if project_config and item.pipeline.name in project_config.pipelines:
project_job_list = \
project_config.pipelines[item.pipeline.name].job_list
- self._createJobGraph(item.change, project_job_list, ret)
+ self._createJobGraph(item, project_job_list, ret)
return ret