Don't override allowed-projects

If an author doesn't want a job to be run except on certain repos,
then they almost certainly didn't want those repos to be able
to inherit from it changing only the override-projects setting so
that the child job could be run.

Instead, perform a set intersection any time that more than one
allowed-projects comes into play in an inheritance path, causing
it to become only more restrictive.

Remove the test from test_model which is covered by the new test.

Change-Id: I7695620ac52f2ae076e9a66818c00de1e8cf7066
This commit is contained in:
James E. Blair 2018-01-26 14:26:18 -08:00
parent 1dd90b3c48
commit 5d71d1a458
9 changed files with 104 additions and 46 deletions

View File

@ -0,0 +1,2 @@
- hosts: all
tasks: []

View File

@ -0,0 +1,27 @@
- pipeline:
name: check
manager: independent
trigger:
gerrit:
- event: patchset-created
success:
gerrit:
Verified: 1
failure:
gerrit:
Verified: -1
- job:
name: base
run: playbooks/base.yaml
parent: null
- job:
name: restricted-job
allowed-projects:
- org/project1
- project:
name: common-config
check:
jobs: []

View File

@ -0,0 +1,10 @@
- job:
name: test-project1
parent: restricted-job
- project:
name: org/project1
check:
jobs:
- test-project1
- restricted-job

View File

@ -0,0 +1,11 @@
- job:
name: test-project2
parent: restricted-job
allowed-projects:
- org/project2
- project:
name: org/project2
check:
jobs:
- test-project2

View File

@ -0,0 +1,5 @@
- project:
name: org/project3
check:
jobs:
- restricted-job

View File

@ -0,0 +1,10 @@
- tenant:
name: tenant-one
source:
gerrit:
config-projects:
- common-config
untrusted-projects:
- org/project1
- org/project2
- org/project3

View File

@ -320,50 +320,6 @@ class TestJob(BaseTestCase):
"to shadow job base in base_project"):
layout.addJob(base2)
def test_job_allowed_projects(self):
job = configloader.JobParser.fromYaml(self.tenant, self.layout, {
'_source_context': self.context,
'_start_mark': self.start_mark,
'name': 'job',
'parent': None,
'allowed-projects': ['project'],
})
self.layout.addJob(job)
project2 = model.Project('project2', self.source)
tpc2 = model.TenantProjectConfig(project2)
self.tenant.addUntrustedProject(tpc2)
context2 = model.SourceContext(project2, 'master',
'test', True)
project_template_parser = configloader.ProjectTemplateParser(
self.tenant, self.layout)
project_parser = configloader.ProjectParser(
self.tenant, self.layout, project_template_parser)
project2_config = project_parser.fromYaml(
[{
'_source_context': context2,
'_start_mark': self.start_mark,
'name': 'project2',
'gate': {
'jobs': [
'job'
]
}
}]
)
self.layout.addProjectConfig(project2_config)
change = model.Change(project2)
# Test master
change.branch = 'master'
item = self.queue.enqueueChange(change)
item.layout = self.layout
with testtools.ExpectedException(
Exception,
"Project project2 is not allowed to run job job"):
item.freezeJobGraph()
def test_job_pipeline_allow_untrusted_secrets(self):
self.pipeline.post_review = False
job = configloader.JobParser.fromYaml(self.tenant, self.layout, {

View File

@ -533,6 +533,36 @@ class TestBranchMismatch(ZuulTestCase):
], ordered=False)
class TestAllowedProjects(ZuulTestCase):
tenant_config_file = 'config/allowed-projects/main.yaml'
def test_allowed_projects(self):
A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertEqual(A.reported, 1)
self.assertIn('Build succeeded', A.messages[0])
B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertEqual(B.reported, 1)
self.assertIn('Project org/project2 is not allowed '
'to run job test-project2', B.messages[0])
C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertEqual(C.reported, 1)
self.assertIn('Project org/project3 is not allowed '
'to run job restricted-job', C.messages[0])
self.assertHistory([
dict(name='test-project1', result='SUCCESS', changes='1,1'),
dict(name='restricted-job', result='SUCCESS', changes='1,1'),
], ordered=False)
class TestCentralJobs(ZuulTestCase):
tenant_config_file = 'config/central-jobs/main.yaml'

View File

@ -1060,7 +1060,8 @@ class Job(object):
"from other projects."
% (repr(self), this_origin))
if k not in set(['pre_run', 'run', 'post_run', 'roles',
'variables', 'required_projects']):
'variables', 'required_projects',
'allowed_projects']):
# TODO(jeblair): determine if deepcopy is required
setattr(self, k, copy.deepcopy(other._get(k)))
@ -1097,6 +1098,12 @@ class Job(object):
self.updateVariables(other.variables)
if other._get('required_projects') is not None:
self.updateProjects(other.required_projects)
if (other._get('allowed_projects') is not None and
self._get('allowed_projects') is not None):
self.allowed_projects = self.allowed_projects.intersection(
other.allowed_projects)
elif other._get('allowed_projects') is not None:
self.allowed_projects = copy.deepcopy(other.allowed_projects)
for k in self.context_attributes:
if (other._get(k) is not None and
@ -2828,7 +2835,7 @@ class Layout(object):
item.debug("No matching pipeline variants for {jobname}".
format(jobname=jobname), indent=2)
continue
if (frozen_job.allowed_projects and
if (frozen_job.allowed_projects is not None and
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))