filter events by user email
On some setup we might restrict a pipeline to trusted users. The new
email_filter will matches the email coming from the event account
attribute.
In Gerrit, each event hold the account in a different field
name so I have simply added a map to find out the correct field.
email_filter works just like comment_filter, fields are ORed and are
considered to be regex.
Change-Id: I775f67b48d5f162106c024f94fe498a049b3fe94
Reviewed-on: https://review.openstack.org/17609
Reviewed-by: James E. Blair <corvus@inaugust.com>
Approved: Monty Taylor <mordred@inaugust.com>
Reviewed-by: Monty Taylor <mordred@inaugust.com>
Tested-by: Jenkins
diff --git a/doc/source/zuul.rst b/doc/source/zuul.rst
index 92b7a6f..416174d 100644
--- a/doc/source/zuul.rst
+++ b/doc/source/zuul.rst
@@ -246,6 +246,10 @@
``code-review: 2`` matches a ``+2`` vote on the code review category.
Multiple approvals may be listed.
+ *email_filter*
+ This is used for any event. It takes a regex applied on the performer
+ email. Example: ``email_filter: .*@example.org$``.
+
*comment_filter*
This is only used for ``comment-added`` events. It accepts a list of
regexes that are searched for in the comment string. If any of these
diff --git a/etc/layout.yaml-sample b/etc/layout.yaml-sample
index 2012e74..eec8553 100644
--- a/etc/layout.yaml-sample
+++ b/etc/layout.yaml-sample
@@ -8,6 +8,16 @@
failure:
verified: -1
+ - name: tests
+ manager: IndependentPipelineManager
+ trigger:
+ - event: patchset-created
+ email_filter: ^.*@example.org$
+ success:
+ verified: 1
+ failure:
+ verified: -1
+
- name: post
manager: IndependentPipelineManager
trigger:
@@ -35,6 +45,8 @@
projects:
- name: example/project
check:
+ - project-merge
+ tests:
- project-merge:
- project-test
gate:
diff --git a/zuul/model.py b/zuul/model.py
index 1398131..9ec4a68 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -520,6 +520,8 @@
# common
self.type = None
self.project_name = None
+ # Representation of the user account that performed the event.
+ self.account = None
# patchset-created, comment-added, etc.
self.change_number = None
self.change_url = None
@@ -565,7 +567,7 @@
class EventFilter(object):
def __init__(self, types=[], branches=[], refs=[], approvals={},
- comment_filters=[]):
+ comment_filters=[], email_filters=[]):
self._types = types
self._branches = branches
self._refs = refs
@@ -573,6 +575,7 @@
self.branches = [re.compile(x) for x in branches]
self.refs = [re.compile(x) for x in refs]
self.comment_filters = [re.compile(x) for x in comment_filters]
+ self.email_filters = [re.compile(x) for x in email_filters]
self.approvals = approvals
def __repr__(self):
@@ -629,6 +632,19 @@
if self.comment_filters and not matches_comment_filter:
return False
+ # We better have an account provided by Gerrit to do
+ # email filtering.
+ if event.account is not None:
+ # email_filters are ORed
+ matches_email_filter = False
+ for email_filter in self.email_filters:
+ account_email = event.account.get('email')
+ if (account_email is not None and
+ email_filter.search(account_email)):
+ matches_email_filter = True
+ if self.email_filters and not matches_email_filter:
+ return False
+
# approvals are ANDed
for category, value in self.approvals.items():
matches_approval = False
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index 60e85f3..31a504e 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -99,7 +99,9 @@
refs=toList(trigger.get('ref')),
approvals=approvals,
comment_filters=
- toList(trigger.get('comment_filter')))
+ toList(trigger.get('comment_filter')),
+ email_filters=
+ toList(trigger.get('email_filter')))
manager.event_filters.append(f)
for config_job in data['jobs']:
diff --git a/zuul/trigger/gerrit.py b/zuul/trigger/gerrit.py
index 3a8f104..892eb36 100644
--- a/zuul/trigger/gerrit.py
+++ b/zuul/trigger/gerrit.py
@@ -59,6 +59,24 @@
event.ref = refupdate.get('refName')
event.oldrev = refupdate.get('oldRev')
event.newrev = refupdate.get('newRev')
+ # Map the event types to a field name holding a Gerrit
+ # account attribute. See Gerrit stream-event documentation
+ # in cmd-stream-events.html
+ accountfield_from_type = {
+ 'patchset-created': 'uploader',
+ 'change-abandoned': 'abandoner',
+ 'change-restored': 'restorer',
+ 'change-merged': 'submitter',
+ 'comment-added': 'author',
+ 'ref-updated': 'submitter',
+ }
+ try:
+ event.account = data.get(accountfield_from_type[event.type])
+ except KeyError:
+ self.log.error("Received unrecongized event type '%s' from Gerrit.\
+ Can not get account information." % event.type)
+ event.account = None
+
self.sched.addEvent(event)
self.gerrit.eventDone()