Bug 1463522 - include .taskcluster.yml hash in hookId; r?tomprince draft
authorDustin J. Mitchell <dustin@mozilla.com>
Tue, 22 May 2018 18:28:08 +0000
changeset 800061 a169487f05fdf703bbd147de7e7fcfacae85020a
parent 800060 1b9028d41a9febe4b4c9ef06d653d8d2f37d98c2
child 800062 89a8071a08a07fa735fde0e3114ca6fdab797f17
push id111248
push userdmitchell@mozilla.com
push dateFri, 25 May 2018 19:58:39 +0000
reviewerstomprince
bugs1463522
milestone62.0a1
Bug 1463522 - include .taskcluster.yml hash in hookId; r?tomprince MozReview-Commit-ID: 7KJGRKuFlna
taskcluster/taskgraph/actions/registry.py
--- a/taskcluster/taskgraph/actions/registry.py
+++ b/taskcluster/taskgraph/actions/registry.py
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import json
 import os
 import re
 import yaml
+import hashlib
 from slugid import nice as slugid
 from types import FunctionType
 from collections import namedtuple
 from taskgraph import create
 from taskgraph.config import load_graph_config
 from taskgraph.util import taskcluster, yaml
 from taskgraph.parameters import Parameters
 from mozbuild.util import memoize
@@ -36,16 +37,24 @@ def is_json(data):
 
 
 @memoize
 def read_taskcluster_yml(filename):
     '''Load and parse .taskcluster.yml, memoized to save some time'''
     return yaml.load_yaml(*os.path.split(filename))
 
 
+@memoize
+def hash_taskcluster_yml(template):
+    """Generate a short hash identifier for the content of .taskcluster.yml"""
+    h = hashlib.sha256()
+    h.update(read_taskcluster_yml_raw(template))
+    return h.hexdigest()[:10]
+
+
 def register_callback_action(name, title, symbol, description, order=10000,
                              context=[], available=lambda parameters: True,
                              schema=None, kind='task', generic=True):
     """
     Register an action callback that can be triggered from supporting
     user interfaces, such as Treeherder.
 
     This function is to be used as a decorator for a callback that takes
@@ -200,20 +209,30 @@ def register_callback_action(name, title
                         'in': taskcluster_yml['tasks'][0],
                     },
                 })
 
             # for kind=hook
             elif kind == 'hook':
                 trustDomain = graph_config['trust-domain']
                 level = parameters['level']
+                tcyml_hash = hash_taskcluster_yml(graph_config.taskcluster_yml)
+
+                # the tcyml_hash is prefixed with `_` in the hookId, so users will be granted
+                # hooks:trigger-hook:project-gecko/in-tree-action-3-myaction_*; if another
+                # action was named `myaction_release`, then the `*` in the scope would also
+                # match that action.  To prevent such an accident, we prohibit `_` in hook
+                # names.
+                if '_' in actionPerm:
+                    raise Exception('`_` is not allowed in action names; use `-`')
+
                 rv.update({
                     'kind': 'hook',
                     'hookGroupId': 'project-{}'.format(trustDomain),
-                    'hookId': 'in-tree-action-{}-{}'.format(level, actionPerm),
+                    'hookId': 'in-tree-action-{}-{}_{}'.format(level, actionPerm, tcyml_hash),
                     'hookPayload': {
                         # provide the decision-task parameters as context for triggerHook
                         "decision": {
                             'action': action,
                             'repository': repository,
                             'push': push,
                             # parameters is long, so fetch it from the actions.json variables
                             'parameters': {'$eval': 'parameters'},