Make gatekeeper recipe hermetic for LUCI

This CL makes a number of changes to the gatekeeper recipe
and recipe module to make it deployable on LUCI:
* It copies the JSON configuration files to be recipe resources
  so that they don't have to be tagged for bundling using
  .gitattributes.
* It copies the helper libraries (build_scan, auth) into the
  recipe resources so that they can be self-contained.
* It adds a vpython environment file so that the gatekeeper_ng
  script can be run in a hermetic environment.
* It updates the python scripts to use LUCI's ambient auth
  credentials, so it doesn't rely (as much) on statically
  deployed credential files.
* It modifies the recipe to call the new hermetic version of
  gatekeeper_ng, and read the new config files.

This CL will be accompanied by an internal CL which makes
corresponding changes to the gatekeeper_internal recipe. It
will be followed by a CL which deletes the old versions of
the gatekeeper scripts and configs.

Bug: 853854
Recipe-Nontrivial-Roll: build_limited_scripts_slave
Change-Id: I0b6cfdaa98800bc239ff38a7a9eec689e5f80bf4
Reviewed-on: https://chromium-review.googlesource.com/c/1480601
Commit-Queue: Aaron Gable <agable@chromium.org>
Reviewed-by: Sean McCullough <seanmccullough@chromium.org>
Reviewed-by: Robbie Iannucci <iannucci@chromium.org>
diff --git a/scripts/slave/README.recipes.md b/scripts/slave/README.recipes.md
index 0e1cb84..2a90a77 100644
--- a/scripts/slave/README.recipes.md
+++ b/scripts/slave/README.recipes.md
@@ -2118,7 +2118,7 @@
 &emsp; **@property**<br>&mdash; **def [platforms](/scripts/slave/recipe_modules/gae_sdk/api.py#58)(self):**
 ### *recipe_modules* / [gatekeeper](/scripts/slave/recipe_modules/gatekeeper)
 
-[DEPS](/scripts/slave/recipe_modules/gatekeeper/__init__.py#1): [build](#recipe_modules-build), [puppet\_service\_account](#recipe_modules-puppet_service_account), [depot\_tools/gitiles][depot_tools/recipe_modules/gitiles], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime], [recipe\_engine/step][recipe_engine/recipe_modules/step]
+[DEPS](/scripts/slave/recipe_modules/gatekeeper/__init__.py#5): [puppet\_service\_account](#recipe_modules-puppet_service_account), [depot\_tools/gitiles][depot_tools/recipe_modules/gitiles], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/python][recipe_engine/recipe_modules/python], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime], [recipe\_engine/step][recipe_engine/recipe_modules/step]
 
 #### **class [Gatekeeper](/scripts/slave/recipe_modules/gatekeeper/api.py#10)([RecipeApi][recipe_engine/wkt/RecipeApi]):**
 
diff --git a/scripts/slave/recipe_modules/gatekeeper/__init__.py b/scripts/slave/recipe_modules/gatekeeper/__init__.py
index 653448e..1929c2a 100644
--- a/scripts/slave/recipe_modules/gatekeeper/__init__.py
+++ b/scripts/slave/recipe_modules/gatekeeper/__init__.py
@@ -1,11 +1,15 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
 DEPS = [
-  'build',
   'depot_tools/gitiles',
   'puppet_service_account',
   'recipe_engine/file',
   'recipe_engine/json',
   'recipe_engine/path',
   'recipe_engine/properties',
+  'recipe_engine/python',
   'recipe_engine/raw_io',
   'recipe_engine/runtime',
   'recipe_engine/step',
diff --git a/scripts/slave/recipe_modules/gatekeeper/api.py b/scripts/slave/recipe_modules/gatekeeper/api.py
index 9900d8d..223a874 100644
--- a/scripts/slave/recipe_modules/gatekeeper/api.py
+++ b/scripts/slave/recipe_modules/gatekeeper/api.py
@@ -103,10 +103,11 @@
         )
 
       try:
-        self.m.build.python(
-          'gatekeeper: %s' % str(tree_name),
-          self.repo_resource('scripts', 'slave', 'gatekeeper_ng.py'),
-          args,
+        self.m.python(
+          name='gatekeeper: %s' % str(tree_name),
+          script=self.resource('gatekeeper_ng.py'),
+          args=args,
+          venv=True
         )
       except self.m.step.StepFailure:
         pass
diff --git a/scripts/slave/recipe_modules/gatekeeper/resources/.vpython b/scripts/slave/recipe_modules/gatekeeper/resources/.vpython
new file mode 100644
index 0000000..97fa123
--- /dev/null
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/.vpython
@@ -0,0 +1,61 @@
+#
+# "vpython" specification file for gatekeeper resource scripts.
+#
+
+python_version: "2.7"
+
+# Used by auth.py
+wheel: <
+  name: "infra/python/wheels/infra_libs-py2"
+  version: "version:2.0.0"
+>
+
+# Transitive dependencies of infra_libs
+wheel: <
+  name: "infra/python/wheels/oauth2client-py2_py3"
+  version: "version:3.0.0"
+>
+wheel: <
+  name: "infra/python/wheels/pyasn1_modules-py2_py3"
+  version: "version:0.0.8"
+>
+wheel: <
+  name: "infra/python/wheels/rsa-py2_py3"
+  version: "version:3.4.2"
+>
+wheel: <
+  name: "infra/python/wheels/httplib2-py2_py3"
+  version: "version:0.10.3"
+>
+wheel: <
+  name: "infra/python/wheels/six-py2_py3"
+  version: "version:1.11.0"
+>
+wheel: <
+  name: "infra/python/wheels/pyasn1-py2_py3"
+  version: "version:0.2.3"
+>
+wheel: <
+  name: "infra/python/wheels/protobuf-py2_py3"
+  version: "version:3.6.1"
+>
+wheel: <
+  name: "infra/python/wheels/requests-py2_py3"
+  version: "version:2.13.0"
+>
+wheel: <
+  name: "infra/python/wheels/google_api_python_client-py2_py3"
+  version: "version:1.6.2"
+>
+wheel: <
+  name: "infra/python/wheels/uritemplate-py2_py3"
+  version: "version:3.0.0"
+>
+wheel: <
+  name: "infra/python/wheels/google-auth-py2_py3"
+  version: "version:1.2.1"
+>
+wheel: <
+  name: "infra/python/wheels/cachetools-py2_py3"
+  version: "version:2.0.1"
+>
diff --git a/scripts/slave/build_scan.py b/scripts/slave/recipe_modules/gatekeeper/resources/build_scan.py
similarity index 93%
rename from scripts/slave/build_scan.py
rename to scripts/slave/recipe_modules/gatekeeper/resources/build_scan.py
index 3f8c66c..50a5e15 100755
--- a/scripts/slave/build_scan.py
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/build_scan.py
@@ -5,11 +5,12 @@
 
 """Scans a list of masters and saves information in a build_db."""
 
-from contextlib import closing
+from contextlib import closing, contextmanager
 import base64
 import httplib2
 import json
 import logging
+import multiprocessing
 import optparse
 import os
 import sys
@@ -17,15 +18,10 @@
 import urllib
 import zlib
 
-from common import chromium_utils
-from slave import build_scan_db
+from infra_libs.luci_auth import LUCICredentials
 
-SCRIPTS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
-                           '..', '..')
+import build_scan_db
 
-# We need master to be on the path to import auth.
-sys.path.insert(0, os.path.join(SCRIPTS_DIR, 'master'))
-from master import auth
 
 # Buildbot status enum.
 SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION, RETRY = range(6)
@@ -36,7 +32,24 @@
 BUILDER_WILDCARD = '*'
 
 ENDPOINT_ROOT = 'https://luci-milo.appspot.com/prpc/'
-SCOPES = ['https://www.googleapis.com/auth/userinfo.email']
+
+
+@contextmanager
+def MultiPool(processes):
+  """Manages a multiprocessing.Pool making sure to close the pool when done.
+
+  This will also call pool.terminate() when an exception is raised (and
+  re-raised the exception to the calling procedure can handle it).
+  """
+  try:
+    pool = multiprocessing.Pool(processes=processes)
+    yield pool
+    pool.close()
+  except:
+    pool.terminate()
+    raise
+  finally:
+    pool.join()
 
 
 def _get_from_milo(endpoint, data, milo_creds=None, http=None):
@@ -48,10 +61,7 @@
   url =  ENDPOINT_ROOT + endpoint
   if not http:
     http = httplib2.Http()
-  if milo_creds:
-    creds = auth.create_service_account_credentials(milo_creds, SCOPES)
-    http = creds.authorize(http)
-    creds.refresh(http)
+  http = LUCICredentials().authorize(http)
   logging.info('fetching %s with %s' % (url, data))
 
   attempts = 0
@@ -148,7 +158,7 @@
               max(finished)] = build_scan_db.gen_build(finished=True)
 
         new_builds[buildername] = current_builds
-  
+
   logging.info('milo output for %s:', master_url)
   for builder in sorted(root_json['builders'].keys()):
     data = root_json['builders'][builder]
@@ -214,7 +224,7 @@
     # The async/get is so that ctrl-c can interrupt the scans.
     # See http://stackoverflow.com/questions/1408356/
     # keyboard-interrupts-with-pythons-multiprocessing-pool
-    with chromium_utils.MultiPool(processes) as pool:
+    with MultiPool(processes) as pool:
       builds = filter(bool, pool.map_async(get_build_json, url_list).get(
           9999999))
   else:
diff --git a/scripts/slave/build_scan_db.py b/scripts/slave/recipe_modules/gatekeeper/resources/build_scan_db.py
similarity index 94%
rename from scripts/slave/build_scan_db.py
rename to scripts/slave/recipe_modules/gatekeeper/resources/build_scan_db.py
index 4a6be33..b434653 100755
--- a/scripts/slave/build_scan_db.py
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/build_scan_db.py
@@ -15,8 +15,7 @@
 import os
 import sys
 
-from common import chromium_utils
-from slave import gatekeeper_ng_config
+import gatekeeper_ng_config
 
 
 DATA_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -70,6 +69,20 @@
   pass
 
 
+def move_file(path, new_path):
+  """Moves the file located at 'path' to 'new_path', if it exists."""
+  try:
+    try:
+      os.remove(file_path)
+    except OSError, e:
+      if e.errno != errno.ENOENT:
+        raise
+    os.rename(path, new_path)
+  except OSError, e:
+    if e.errno != errno.ENOENT:
+      raise
+
+
 def gen_db(**kwargs):
   """Helper function to generate a default database."""
   defaults = [
@@ -140,7 +153,7 @@
       new_fn = '%s.old' % filename
       logging.warn('error loading %s: %s, moving to %s' % (
           filename, e, new_fn))
-      chromium_utils.MoveFile(filename, new_fn)
+      move_file(filename, new_fn)
 
   return build_db
 
diff --git a/scripts/slave/unittests/build_scan_test.py b/scripts/slave/recipe_modules/gatekeeper/resources/build_scan_test.py
similarity index 97%
rename from scripts/slave/unittests/build_scan_test.py
rename to scripts/slave/recipe_modules/gatekeeper/resources/build_scan_test.py
index 0ee6093..14ff267 100755
--- a/scripts/slave/unittests/build_scan_test.py
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/build_scan_test.py
@@ -16,7 +16,7 @@
 
 import test_env  # pylint: disable=relative-import
 
-from slave import build_scan
+import build_scan
 
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 
diff --git a/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper.json b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper.json
new file mode 100644
index 0000000..a91606c
--- /dev/null
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper.json
@@ -0,0 +1,1104 @@
+{
+  "comment": ["This is a configuration file for gatekeeper_ng.py",
+              "Look in gatekeeper_ng_config.py for documentation on ",
+              "this files's format."],
+
+  "masters": {
+    "https://build.chromium.org/p/chromium": [
+      {
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+
+        "builders": {
+          "linux-rel": {
+            "tree_notify": [
+              "thomasanderson@chromium.org"
+            ]
+          },
+          "win32-rel": {
+            "categories": [
+              "chromium_windows"
+            ]
+          },
+          "*": {}
+        },
+        "excluded_builders": [
+          "win-dbg",
+          "win32-dbg"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/chromium.android": [
+      {
+        "categories": [
+          "chromium_android",
+          "experimental_tests"
+        ],
+        "builders": {
+          "Android ASAN (dbg)": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "Android Cronet ARM64 Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet ARM64 Builder (dbg)": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet ARMv6 Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet Builder (dbg)": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet KitKat Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet Lollipop Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet Marshmallow 64bit Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet Marshmallow 64bit Perf": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet MIPS Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet x86 Builder": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android Cronet x86 Builder (dbg)": {
+            "tree_notify": [
+              "cronet-sheriff+build@google.com"
+            ],
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "Android arm Builder (dbg)": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "Android arm64 Builder (dbg)": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "Cast Android (dbg)": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "KitKat Phone Tester (rel)": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "Marshmallow Phone Tester (rel)": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "android-kitkat-arm-rel": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "android-marshmallow-arm64-rel": {
+            "categories": [
+              "chromium_tree_closer"
+            ]
+          },
+          "Deterministic Android (dbg)": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "tree_notify": [
+              "agrieve@chromium.org"
+            ]
+          },
+          "Deterministic Android": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "tree_notify": [
+              "agrieve@chromium.org"
+            ]
+          },
+          "*": {}
+        },
+        "excluded_builders": [
+          "android-cronet-arm-dbg",
+          "android-cronet-arm-rel",
+          "android-cronet-arm64-dbg",
+          "android-cronet-arm64-rel",
+          "android-cronet-asan-arm-rel",
+          "android-cronet-kitkat-arm-rel",
+          "android-cronet-lollipop-arm-rel",
+          "android-cronet-marshmallow-arm64-rel",
+          "android-cronet-x86-dbg",
+          "android-cronet-x86-rel",
+          "android-incremental-dbg",
+          "Oreo Phone Tester"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/chromium.android.fyi": [
+      {
+        "builders": {
+          "Memory Infra Tester": {
+            "tree_notify": [
+              "chrome-memory-sheriffs+bots@google.com"
+            ],
+            "forgiving_optional": [ "*" ]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromiumos": [
+      {
+        "comment": ["master.chromiumos"],
+        "forgive_all": true,
+        "builders": {
+          "*": {
+            "forgiving_optional": ["*"]
+          }
+        },
+        "excluded_builders": [ "*" ]
+      }
+    ],
+    "https://build.chromium.org/p/chromium.chromiumos": [
+      {
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+        "builders": {
+          "*": {}
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.gatekeeper": [
+      {
+        "tree_notify": [
+          "chromium-build-heartbeat@chromium-gatekeeper-sentry.appspotmail.com"
+        ],
+
+        "builders": {
+          "Chromium Gatekeeper Failure": {
+            "forgiving_optional": [
+              "*"
+            ]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.gpu": [
+      {
+        "tree_notify": ["chrome-gpu-build-failures@google.com"],
+        "sheriff_classes": ["sheriff", "sheriff_gpu"],
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+        "builders": {
+          "Mac 10.8 Release (Intel)": {
+            "excluded_steps": [
+              "maps_pixel_test"
+            ]
+          },
+          "*": {}
+        },
+        "comment": [
+          "Keep excluded builders in sync with the gpu closers list in",
+          "masters/master.chromium/templates/announce.html.",
+          "Mac Release (ATI): crbug.com/395305"
+        ],
+        "excluded_builders" : [
+          "Android Debug (Nexus 7)",
+          "GPU Linux Builder (dbg)",
+          "GPU Mac Builder (dbg)",
+          "GPU Win Builder (dbg)",
+          "Linux Debug (NVIDIA)",
+          "Mac 10.8 Debug (Intel)",
+          "Mac Debug (Intel)",
+          "Mac Release (ATI)",
+          "Mac Retina Debug",
+          "Win7 Debug (NVIDIA)",
+          "Win8 Debug (NVIDIA)"
+        ],
+        "comment": [
+          "Any steps whose results must be temporarily ignored (e.g.",
+          "due to flakiness) can be added here.",
+          "Remove webgl_conformance_tests after crbug.com/383963 fixed"
+        ],
+        "excluded_steps": [
+          "webgl_conformance_tests"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/chromium.clang": [
+      {
+        "close_tree": false,
+        "builders": {
+          "ToTLinux*": {
+            "forgiving_optional": [ "*" ],
+            "tree_notify": [
+              "thomasanderson@chromium.org"
+            ]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.infra.cron": [
+      {
+        "close_tree": false,
+        "builders": {
+          "Build From Tarball": {
+            "forgiving_optional": ["*"],
+            "tree_notify": [
+              "raphael.kubo.da.costa@intel.com"
+            ]
+          },
+          "publish_tarball": {
+            "forgiving_optional": ["*"],
+            "tree_notify": [
+              "raphael.kubo.da.costa@intel.com",
+              "thomasanderson@chromium.org"
+            ]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.infra": [
+      {
+        "builders": {
+          "infra-continuous-xenial-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-trusty-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-trusty-32": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-precise-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-precise-32": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-mac-10.13-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-win-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-win-32": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "infra-continuous-recipe-tests": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+
+          "luci-gae-continuous-trusty-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-gae-continuous-mac": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-gae-continuous-win": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+
+          "luci-go-continuous-mac-10.13-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-go-continuous-mac-10.9-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-go-continuous-precise-32": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-go-continuous-trusty-32": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-go-continuous-trusty-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-go-continuous-win10-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-go-continuous-win7-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "luci-go-continuous-xenial-64": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+
+          "build-recipe-tests": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "depot_tools-recipes-tests": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          },
+          "recipe_engine-recipes-tests": {
+            "categories": [
+              "infra_tree_closer"
+            ]
+          }
+
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.linux": [
+      {
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+        "builders": {
+          "*": {}
+        },
+        "tree_notify": [
+          "thomasanderson@chromium.org"
+        ]
+      },
+      {
+        "builders": {
+          "fuchsia-arm64-cast": {
+            "forgiving_optional": ["*"]
+          },
+          "fuchsia-x64-cast": {
+            "forgiving_optional": ["*"]
+          }
+        }
+      },
+      {
+        "builders": {
+          "Deterministic Linux": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "tree_notify": [
+              "shinyak@chromium.org",
+              "tikuta@chromium.org",
+              "ukai@chromium.org",
+              "yyanagisawa@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "linux-ozone-rel": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "tree_notify": [
+              "fwang@chromium.org",
+              "maksim.sisov@chromium.org",
+              "rjkroege@chromium.org",
+              "thomasanderson@chromium.org",
+              "timbrown@chromium.org",
+              "tonikitoo@chromium.org"
+            ],
+            "forgiving_optional": [
+              "*"
+            ]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.mac": [
+      {
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+        "excluded_builders" : [
+          "mac-osxbeta-rel"
+        ],
+        "builders": {
+          "ios-device": {
+            "sheriff_classes": ["sheriff_ios"]
+          },
+          "ios-device-xcode-clang": {
+            "close_tree": false,
+            "sheriff_classes": ["sheriff_ios"]
+          },
+          "ios-simulator": {
+            "sheriff_classes": ["sheriff_ios"],
+            "closing_optional": [],
+            "comment": ["closing_optional due to crbug.com/393861"]
+          },
+          "ios-simulator-full-configs": {
+            "sheriff_classes": ["sheriff_ios"],
+            "closing_optional": []
+          },
+          "ios-simulator-xcode-clang": {
+            "close_tree": false,
+            "sheriff_classes": ["sheriff_ios"]
+          },
+          "ios-uirefresh-simulator": {
+            "sheriff_classes": ["sheriff_ios"],
+            "close_tree": false
+          },
+          "Mac GN (dbg)": {
+            "close_tree": false
+          },
+          "*": {}
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.memory": [
+      {
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+        "builders": {
+          "Linux*": {
+            "tree_notify": [
+              "thomasanderson@chromium.org"
+            ]
+          },
+          "*": {}
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.perf": [
+      {
+        "forgive_all": "true",
+
+        "subject_template": "%(project_name)s %(builder_name)s %(result)s",
+
+        "builders": {
+          "Android Builder Perf": {
+            "tree_notify": [
+              "chrome-binary-size-sheriff@grotations.appspotmail.com"
+            ]
+          },
+          "Android Compile": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "forgiving_optional": []
+          },
+          "Android arm64 Builder": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "forgiving_optional": []
+          },
+          "Android arm64 Compile": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "forgiving_optional": []
+          },
+          "Linux Builder": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "forgiving_optional": []
+          },
+          "Mac Builder": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "forgiving_optional": []
+          },
+          "Win Builder": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "forgiving_optional": []
+          },
+          "Win x64 Builder": {
+            "categories": [
+              "chromium_tree_closer",
+              "experimental_tests"
+            ],
+            "forgiving_optional": []
+          }
+        },
+
+        "categories": [
+          "chromium_perf_steps"
+        ],
+
+        "builders": {
+          "*": {}
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.tools.build": [
+      {
+        "builders": {
+          "cipd-test-end-to-end_mac": {
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "cipd-test-end-to-end_trusty64": {
+            "closing_optional": [
+              "*"
+            ]
+          },
+          "cipd-test-end-to-end_win64": {
+            "closing_optional": [
+              "*"
+            ]
+          }
+        },
+        "forgive_all": "true",
+        "tree_notify": [
+          "tandrii+build-recipes-end-to-end@google.com"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/chromium.webkit": [
+      {
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+        "builders": {
+          "*": {}
+        }
+      }
+    ],
+    "https://build.chromium.org/p/chromium.win": [
+      {
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+
+        "comment": [
+          "Bot should be sheriffed, but is very broken and flaky, and hasn't",
+          "been fixed. Excluding it so it doesn't show up on SOM. See ",
+          "crbug.com/876224 for more details."
+        ],
+        "excluded_builders" : [
+            "Win10 Tests x64 (dbg)"
+        ],
+        "builders": {
+          "*": {}
+        }
+      }
+    ],
+    "https://build.chromium.org/p/client.boringssl": [
+      {
+        "tree_notify": [
+          "boringssl@google.com"
+        ],
+
+        "forgive_all": "true",
+
+        "builders": {
+          "*": {
+            "closing_optional": [
+              "*"
+            ]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/client.crashpad": [
+      {
+        "builders": {
+          "*": {
+            "closing_optional": [
+              "*"
+            ]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/client.catapult": [
+      {
+        "forgive_all": "true",
+        "tree_notify": [
+          "catapult-sheriff@chromium.org"
+        ],
+        "builders": {
+          "*": {
+            "forgiving_optional": ["*"]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/client.nacl": [
+      {
+        "categories": [
+          "nacl_all"
+        ],
+        "sheriff_classes": ["sheriff_nacl"],
+        "excluded_builders" : [
+            "precise_64-newlib-arm_qemu-pnacl-buildonly-spec",
+            "oneiric_32-newlib-arm_hw-pnacl-panda-spec"
+        ],
+        "builders": {
+          "*": {}
+        },
+        "tree_notify": [
+            "bradnelson+nacl-gatekeeper@chromium.org"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/client.nacl.sdk": [
+      {
+        "forgive_all": true,
+        "categories": [
+          "nacl_all"
+        ],
+        "builders": {
+          "*": {}
+        },
+        "tree_notify": [
+            "bradnelson@chromium.org",
+            "sbc@chromium.org",
+            "binji@chromium.org"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/client.nacl.ports": [
+      {
+        "categories": [
+          "nacl_all"
+        ],
+        "sheriff_classes": ["sheriff_nacl"],
+        "builders": {
+          "*": {}
+        },
+        "tree_notify": [
+            "bradnelson@chromium.org"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/client.pdfium": [
+      {
+        "categories": [
+          "pdfium_all"
+        ],
+        "builders": {
+          "*": {}
+        },
+        "tree_notify": [
+            "dsinclair@chromium.org",
+            "thestig@chromium.org"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/client.webrtc": [
+      {
+        "tree_notify": [
+          "webrtc-sheriff-mtv@grotations.appspotmail.com",
+          "webrtc-sheriff-sto@grotations.appspotmail.com"
+        ],
+        "categories": [
+          "chromium_tree_closer",
+          "experimental_tests"
+        ],
+        "builders": {
+          "*": { "categories": [ "webrtc_all"] }
+        },
+        "excluded_builders": [
+          "*UWP*"
+        ]
+      }
+    ],
+    "https://build.chromium.org/p/chromium.fyi": [
+      {
+        "builders": {
+          "Closure Compilation Linux": {
+            "tree_notify": [
+              "dbeam+closure-bots@chromium.org",
+              "fukino+closure-bots@chromium.org",
+              "hirono+closure-bots@chromium.org",
+              "vitalyp@chromium.org"
+            ],
+            "forgiving_optional": [
+              "update_scripts",
+              "setup_build",
+              "bot_update"
+            ],
+            "closing_optional": [
+              "generate_gyp_files",
+              "compile",
+              "generate_v2_gyp_files",
+              "compile_v2"
+            ]
+          },
+          "fuchsia-fyi-arm64-rel": {
+            "forgiving_optional": ["*"]
+          },
+          "fuchsia-fyi-x64-dbg": {
+            "forgiving_optional": ["*"]
+          },
+          "fuchsia-fyi-x64-rel": {
+            "forgiving_optional": ["*"]
+          },
+          "Linux ARM": {
+            "tree_notify": [
+              "thomasanderson@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "Linux Xenial": {
+            "tree_notify": [
+              "thomasanderson@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "Mojo Android": {
+            "tree_notify": [
+              "network-service-sheriffs@chromium.org"
+            ],
+            "forgive_all": "true",
+            "forgiving_optional": ["*"]
+          },
+          "Mojo Linux": {
+            "tree_notify": [
+              "network-service-sheriffs@chromium.org"
+            ],
+            "forgive_all": "true",
+            "forgiving_optional": ["*"]
+          },
+          "Site Isolation Android": {
+            "tree_notify": [
+              "nasko+fyi-bots@chromium.org",
+              "creis+fyi-bots@chromium.org",
+              "lukasza+fyi-bots@chromium.org",
+              "alexmos+fyi-bots@chromium.org"
+            ],
+            "forgiving_optional": [
+              "*"
+            ]
+          },
+          "Jumbo Linux x64": {
+            "tree_notify": [
+              "bratell+jumbo-builds@opera.com",
+              "brucedawson@chromium.org",
+              "dpranke@chromium.org",
+              "mostynb+jumbo@vewd.com"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "Jumbo Mac": {
+            "tree_notify": [
+              "bratell+jumbo-builds@opera.com",
+              "brucedawson@chromium.org",
+              "dpranke@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "Jumbo Win x64": {
+            "tree_notify": [
+              "bratell+jumbo-builds@opera.com",
+              "brucedawson@chromium.org",
+              "dpranke@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "CFI Linux ToT": {
+            "tree_notify": [
+              "pcc@chromium.org"
+            ],
+            "forgive_all": "true",
+            "forgiving_optional": ["*"],
+            "subject_template": "buildbot %(result)s in %(project_name)s on %(builder_name)s, revision %(revision)s"
+          },
+          "CFI Linux CF": {
+            "tree_notify": [
+              "pcc@chromium.org"
+            ],
+            "forgive_all": "true",
+            "forgiving_optional": ["*"],
+            "subject_template": "buildbot %(result)s in %(project_name)s on %(builder_name)s, revision %(revision)s"
+          },
+          "Win 10 Fast Ring": {
+            "tree_notify": [
+              "wfh@chromium.org"
+            ],
+            "forgive_all": "true",
+            "forgiving_optional": ["*"]
+          },
+          "linux-blink-heap-verification": {
+            "tree_notify": [
+              "mlippautz+fyi-bots@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "linux-annotator-rel": {
+            "tree_notify": [
+              "georgesak@chromium.org",
+              "nicolaso@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          },
+          "win-annotator-rel": {
+            "tree_notify": [
+              "georgesak@chromium.org",
+              "nicolaso@chromium.org"
+            ],
+            "forgiving_optional": ["*"]
+          }
+        }
+      }
+    ],
+    "https://build.chromium.org/p/tryserver.chromium.linux": [
+      {
+        "close_tree": false,
+        "tree_notify": [
+          "chromium-component-mapping@google.com"
+        ],
+        "builders": {
+          "linux_chromium_component_updater": {
+            "forgiving_optional": ["*"]
+          }
+        }
+      }
+    ]
+  },
+
+  "categories": {
+    "chromium_memory_full": {
+      "closing_optional": [
+        "*"
+      ]
+    },
+
+    "chromium_tree_closer": {
+      "closing_optional": [
+        "bot_update",
+        "compile",
+        "gclient runhooks",
+        "runhooks",
+        "update"
+      ],
+      "sheriff_classes": ["sheriff"],
+      "status_template": "Tree is closed (Automatic: \"%(unsatisfied)s\" on %(build_url)s \"%(builder_name)s\" from %(revision)s: %(blamelist)s)"
+    },
+
+    "chromium_windows": {
+      "forgiving_optional": [
+        "svnkill",
+        "taskkill"
+      ]
+    },
+
+    "chromium_compile": {
+      "closing_optional": [
+        "compile"
+      ]
+    },
+
+    "chromium_archive_build": {
+      "forgiving_optional": [
+        "archive_build"
+      ]
+    },
+
+    "chromium_perf_steps": {
+      "closing_optional": [
+        "*"
+      ]
+    },
+
+    "chromium_android": {
+      "excluded_steps": [
+        "slave_steps"
+      ],
+      "forgiving_optional": [
+        "compile"
+      ],
+      "sheriff_classes": ["sheriff_android"]
+    },
+
+    "experimental_tests": {
+      "excluded_steps": [
+        "*(experimental)*"
+      ]
+    },
+
+    "infra_tree_closer": {
+      "closing_optional": [
+        "*"
+      ],
+      "status_template": "Tree is closed (Automatic: \"%(unsatisfied)s\" on %(build_url)s \"%(builder_name)s\" from %(revision)s: %(blamelist)s)",
+      "tree_notify": [
+        "tandrii+infra-continuous-self-appointed-gardener@google.com"
+      ]
+    },
+    "nacl_all": {
+      "closing_optional": [
+        "compile",
+        "gn",
+        "gclient runhooks",
+        "runhooks",
+        "Presubmit",
+        "Static-Initializers",
+        "Check",
+        "Unittests",
+        "OptimizeForSize",
+        "Mjsunit",
+        "Webkit",
+        "Benchmarks",
+        "Test262",
+        "Test262-es6",
+        "Mozilla",
+        "GCMole arm",
+        "GCMole arm64",
+        "GCMole ia32",
+        "GCMole x64",
+        "Simple Leak Check"
+      ],
+      "forgiving_optional": [
+        "update_scripts",
+        "update",
+        "annotate"
+      ],
+      "subject_template": "buildbot %(result)s in %(project_name)s on %(builder_name)s, revision %(revision)s"
+    },
+    "pdfium_all": {
+      "closing_optional": [
+        "*"
+      ],
+      "forgiving_optional": [
+        "update_scripts",
+        "steps"
+      ]
+    },
+    "webrtc_all": {
+      "forgiving_optional": [
+        "bot_update",
+        "package build",
+        "extract build",
+        "cleanup_temp",
+        "taskkill"
+      ],
+      "closing_optional": [
+        "compile",
+        "gn"
+      ]
+    }
+  }
+}
diff --git a/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_emoji.json b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_emoji.json
new file mode 100644
index 0000000..996db33
--- /dev/null
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_emoji.json
@@ -0,0 +1,115 @@
+[
+    "Want more emoji? CLs welcome! https://goo.gl/zybKBn",
+    "☃",
+    "☀ Tree is open ☀",
+    "٩◔̯◔۶",
+    "☺",
+    "(´・ω・`)",
+    "(΄◞ิ౪◟ิ‵ )",
+    "(╹◡╹)",
+    "♩‿♩",
+    "(/・ω・)/",
+    " ʅ(◔౪◔ ) ʃ",
+    "ヽ(^o^)丿",
+    "\\(・ω・)/",
+    "\(^o^)/",
+    "キタ━━━━(゚∀゚)━━━━ッ!!",
+    "ヽ(^。^)ノ",
+    "(゚д゚)",
+    "ヽ(´ω`*人*´ω`)ノ",
+    " ゚+。:.゚ヽ(*´∀`)ノ゚.:。+゚",
+    "(゜ー゜*)ネッ!",
+    " ♪d(´▽`)b♪オールオッケィ♪",
+    "(ノ≧∀≦)ノ・‥…",
+    "☆(ゝω・)vキャピ",
+    "ლ(╹◡╹ლ)",
+    "ƪ(•̃͡ε•̃͡)∫ʃ",
+    "(•_•)",
+    "( ་ ⍸ ་ )",
+    "(☉౪ ⊙)",
+    "˙ ͜ʟ˙",
+    "( ఠൠఠ )",
+    "☆.。.:*・゚☆.。.:*・゚☆祝☆゚・*:.。.☆゚・*:.。.☆",
+    "༼ꉺɷꉺ༽",
+    "◉_◉",
+    "ϵ( ‘Θ’ )϶",
+    "ヾ(⌐■_■)ノ♪",
+    "(◡‿◡✿)",
+    "★.:゚+。☆ (●´v`○)bォメデトd(○´v`●)☆.:゚+。★",
+    "(☆.☆)",
+    "オメデトー♪c(*゚ー^)ノ*・'゚☆。.:*:・'☆'・:*:.",
+    "☆.。.:*・°☆.。.:*・°☆",
+    "ʕ •ᴥ•ʔ",
+    "☼.☼",
+    "⊂(・(ェ)・)⊃",
+    "(ノ≧∇≦)ノ ミ ┸━┸",
+    "UwU",
+    "Paç fat!",
+    "Sretno",
+    "Hodně štěstí!",
+    "Held og lykke!",
+    "Veel geluk!",
+    "Edu!",
+    "lykkyä tykö",
+    "Viel Glück!",
+    "Καλή τύχη!",
+    "Sok szerencsét kivánok!",
+    "Gangi þér vel!",
+    "Go n-éirí an t-ádh leat!",
+    "Buona fortuna!",
+    "Laimīgs gadījums!",
+    "Sėkmės!",
+    "Vill Gléck!",
+    "Со среќа!",
+    "Powodzenia!",
+    "Boa sorte!",
+    "Noroc!",
+    "Срећно",
+    "Veľa šťastia!",
+    "Lycka till!",
+    "Bona sort!",
+    "Zorte on!",
+    "Góða eydnu",
+    "¡Boa fortuna!",
+    "Bona fortuna!",
+    "Xewqat sbieħ",
+    "Aigh vie!",
+    "Pob lwc!",
+    " موفق باشيد",
+    "İyi şanslar!",
+    "Bonŝancon!",
+    "祝你好运!",
+    "祝你好運!",
+    "頑張って!",
+    "សំណាងល្អ ",
+    "행운을 빌어요",
+    "शुभ कामना ",
+    "โชคดี!",
+    "Chúc may mắn!",
+    "بالتوفيق!",
+    "Sterkte!",
+    "Ke o lakaletsa mohlohonolo",
+    "Uve nemhanza yakanaka",
+    "Kila la kheri!",
+    "Amathamsanqa",
+    "Ngikufisela iwela!",
+    "Bonne chance!",
+    "¡Buena suerte!",
+    "Good luck!",
+    "Semoga Beruntung!",
+    "Selamat Maju Jaya!",
+    "Ia manuia",
+    "Suwertehin ka sana",
+    "Удачи!",
+    "Հաջողությո'ւն",
+    "Іске сәт",
+    "Амжилт хүсье",
+    "удачі!",
+    "Da legst di nieda!",
+    "Gell, da schaugst?",
+    "Ois Guade",
+    "शुभ कामना!",
+    "நல் வாழ்த்துக்கள் ",
+    "అంతా శుభం కలగాలి! " ,
+    ":')"
+]
diff --git a/scripts/slave/gatekeeper_ng.py b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng.py
similarity index 98%
rename from scripts/slave/gatekeeper_ng.py
rename to scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng.py
index 2250a56..59cd943 100755
--- a/scripts/slave/gatekeeper_ng.py
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng.py
@@ -31,11 +31,12 @@
 import urllib
 import urllib2
 
-from slave import build_scan
-from slave import build_scan_db
-from slave import gatekeeper_ng_config
+from infra_libs.luci_auth import LUCICredentials
 
-from master import auth
+import build_scan
+import build_scan_db
+import gatekeeper_ng_config
+
 
 DATA_DIR = os.path.dirname(os.path.abspath(__file__))
 
@@ -471,9 +472,6 @@
   return reduce(operator.or_, sheriff_sets, set())
 
 
-SCOPES = ['https://www.googleapis.com/auth/userinfo.email']
-
-
 def _http_req_auth(url, method, body, http):
   http = http or httplib2.Http()
 
@@ -498,10 +496,7 @@
   }
 
   http = httplib2.Http()
-  if creds:
-    creds = auth.create_service_account_credentials(creds, SCOPES)
-    http = creds.authorize(http)
-    creds.refresh(http)
+  http = LUCICredentials().authorize(http)
 
   code, content = _http_req_auth(
       url, "POST", urllib.urlencode({'json': json.dumps(data)}), http)
@@ -835,7 +830,7 @@
   parser.add_argument('--email-domain', default='google.com',
                       help='default email domain to add to users without one')
   parser.add_argument('--sheriff-url',
-                      default='http://build.chromium.org/p/chromium/%s.js',
+                      default='https://rota-ng.appspot.com/legacy/%s.js',
                       help='URL pattern for the current sheriff list')
   parser.add_argument('--parallelism', default=16,
                       help='up to this many builds can be queried '
diff --git a/scripts/slave/gatekeeper_ng_config.py b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_config.py
similarity index 100%
rename from scripts/slave/gatekeeper_ng_config.py
rename to scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_config.py
diff --git a/scripts/slave/unittests/gatekeeper_ng_config_test.py b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_config_test.py
similarity index 98%
rename from scripts/slave/unittests/gatekeeper_ng_config_test.py
rename to scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_config_test.py
index 3048f78..d2784c2 100755
--- a/scripts/slave/unittests/gatekeeper_ng_config_test.py
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_config_test.py
@@ -15,7 +15,7 @@
 
 import test_env  # pylint: disable=relative-import
 
-from slave import gatekeeper_ng_config
+import gatekeeper_ng_config
 
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 
diff --git a/scripts/slave/unittests/gatekeeper_ng_test.py b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_test.py
similarity index 99%
rename from scripts/slave/unittests/gatekeeper_ng_test.py
rename to scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_test.py
index c68944a..9281c80 100755
--- a/scripts/slave/unittests/gatekeeper_ng_test.py
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_ng_test.py
@@ -30,10 +30,10 @@
 
 import test_env  # pylint: disable=relative-import
 
-from slave import gatekeeper_ng
-from slave import gatekeeper_ng_config
-from slave import build_scan
-from slave import build_scan_db
+import gatekeeper_ng
+import gatekeeper_ng_config
+import build_scan
+import build_scan_db
 
 
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
diff --git a/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_trees.json b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_trees.json
new file mode 100644
index 0000000..c64e493
--- /dev/null
+++ b/scripts/slave/recipe_modules/gatekeeper/resources/gatekeeper_trees.json
@@ -0,0 +1,170 @@
+{
+    "chromiumos": {
+        "masters": {
+            "https://build.chromium.org/p/chromiumos": ["*"],
+            "https://build.chromium.org/p/chromium.chromiumos": ["*"]
+        }
+    },
+    "build": {
+        "build-db": "build_db.json",
+        "masters": {
+            "https://build.chromium.org/p/chromium.tools.build": ["*"]
+        }
+    },
+    "chromium": {
+        "build-db": "waterfall_build_db.json",
+        "masters": {
+            "https://build.chromium.org/p/chromium": ["*"],
+            "https://build.chromium.org/p/chromium.chromiumos": ["*"],
+            "https://build.chromium.org/p/chromium.gpu": ["*"],
+            "https://build.chromium.org/p/chromium.linux": ["*"],
+            "https://build.chromium.org/p/chromium.mac": ["*"],
+            "https://build.chromium.org/p/chromium.memory": ["*"],
+            "https://build.chromium.org/p/chromium.webkit": ["*"],
+            "https://build.chromium.org/p/chromium.win": ["*"]
+        },
+        "open-tree": true,
+        "password-file": "/creds/gatekeeper/chromium_status_password",
+        "revision-properties": "got_revision_cp",
+        "set-status": true,
+        "status-url": "https://chromium-status.appspot.com",
+        "track-revisions": true
+    },
+    "android": {
+        "open-tree": false,
+        "set-status": false,
+        "masters": {
+            "https://build.chromium.org/p/chromium.android": ["*"],
+            "https://build.chromium.org/p/chromium": ["Android"],
+            "https://build.chromium.org/p/chromium.webkit": [
+                "Android Builder", "Webkit Android (Nexus4)"
+            ]
+        }
+    },
+    "infra": {
+        "build-db": "infra_db.json",
+        "masters": {
+            "https://build.chromium.org/p/chromium.infra": ["*"]
+        },
+        "open-tree": true,
+        "status-url": "https://infra-status.appspot.com",
+        "set-status": true,
+        "password-file": "/creds/gatekeeper/infra_status_password"
+    },
+    "ios": {
+        "build-db": "ios_db.json",
+        "open-tree": false,
+        "set-status": false,
+        "masters": {
+          "https://build.chromium.org/p/chromium.mac": [
+              "ios-device",
+              "ios-device-xcode-clang",
+              "ios-simulator",
+              "ios-simulator-full-configs",
+              "ios-simulator-xcode-clang"
+          ]
+        }
+    },
+    "nacl": {
+        "build-db": "nacl_build_db.json",
+        "masters": {
+            "https://build.chromium.org/p/client.nacl": ["*"]
+        },
+        "open-tree": true,
+        "password-file": "/creds/gatekeeper/nacl_status_password",
+        "revision-properties": "got_revision_cp",
+        "set-status": true,
+        "status-url": "https://nativeclient-status.appspot.com",
+        "track-revisions": true
+    },
+    "nacl-sdk": {
+        "masters": {
+            "https://build.chromium.org/p/client.nacl.sdk": ["*"]
+        },
+        "revision-properties": "got_revision_cp",
+        "track-revisions": true
+    },
+    "nacl-ports": {
+        "build-db": "nacl_ports_build_db.json",
+        "masters": {
+            "https://build.chromium.org/p/client.nacl.ports": ["*"]
+        },
+        "open-tree": true,
+        "password-file": "/creds/gatekeeper/nacl_ports_status_password",
+        "revision-properties": "got_revision_cp",
+        "set-status": true,
+        "status-url": "https://naclports-status.appspot.com",
+        "track-revisions": false
+    },
+    "pdfium": {
+        "build-db": "pdfium_build_db.json",
+        "masters": {
+            "https://build.chromium.org/p/client.pdfium": ["*"]
+        },
+        "open-tree": true,
+        "password-file": "/creds/gatekeeper/pdfium_status_password",
+        "revision-properties": "got_revision_cp",
+        "set-status": true,
+        "status-url": "https://pdfium-status.appspot.com",
+        "track-revisions": true
+    },
+    "v8-tree-closers": {
+        "build-db": "v8_tree_closers_build_db.json",
+        "gitiles-config": {
+          "repo_url": "https://chromium.googlesource.com/v8/v8",
+          "ref": "refs/heads/infra/config",
+          "path": "gatekeeper/tree_closers.json"
+        },
+        "masters": {
+            "https://build.chromium.org/p/client.v8": ["*"],
+            "https://build.chromium.org/p/client.v8.fyi": ["*"],
+            "https://build.chromium.org/p/client.v8.ports": ["*"]
+        },
+        "open-tree": true,
+        "password-file": "/creds/gatekeeper/v8_status_password",
+        "revision-properties": "got_revision_cp",
+        "set-status": true,
+        "status-url": "https://v8-status.appspot.com",
+        "track-revisions": true
+    },
+    "v8-mail-notifiers": {
+        "build-db": "v8_mail_notifiers_build_db.json",
+        "gitiles-config": {
+          "repo_url": "https://chromium.googlesource.com/v8/v8",
+          "ref": "refs/heads/infra/config",
+          "path": "gatekeeper/mail_notifiers.json"
+        },
+        "masters": {
+            "https://build.chromium.org/p/client.v8": ["*"],
+            "https://build.chromium.org/p/client.v8.chromium": ["*"],
+            "https://build.chromium.org/p/client.v8.fyi": ["*"]
+        }
+    },
+    "webrtc": {
+        "build-db": "webrtc_build_db.json",
+        "masters": {
+            "https://build.chromium.org/p/client.webrtc": ["*"]
+        },
+        "open-tree": true,
+        "password-file": "/creds/gatekeeper/webrtc_status_password",
+        "revision-properties": "got_revision",
+        "set-status": true,
+        "status-url": "https://webrtc-status.appspot.com",
+        "track-revisions": true
+    },
+    "chromium.perf": {
+        "masters": {
+            "https://build.chromium.org/p/chromium.perf": ["*"]
+        }
+    },
+    "non-closers": {
+        "filter-domain": "chromium.org,google.com,intel.com,opera.com,vewd.com",
+        "masters": {
+            "https://build.chromium.org/p/chromium.fyi": ["*"],
+            "https://build.chromium.org/p/chromium.infra.cron": ["*"],
+            "https://build.chromium.org/p/client.boringssl": ["*"],
+            "https://build.chromium.org/p/client.catapult": ["*"],
+            "https://build.chromium.org/p/client.crashpad": ["*"]
+        }
+    }
+}
diff --git a/scripts/slave/recipe_modules/gatekeeper/test_api.py b/scripts/slave/recipe_modules/gatekeeper/test_api.py
index b53f9a3..0edd63c 100644
--- a/scripts/slave/recipe_modules/gatekeeper/test_api.py
+++ b/scripts/slave/recipe_modules/gatekeeper/test_api.py
@@ -11,7 +11,7 @@
 # available as test data whereever the simulation is run.
 PROD_TREES_FILE = os.path.normpath(
     os.path.join(os.path.dirname(os.path.abspath(__file__)),
-    '..', '..', 'gatekeeper_trees.json'))
+    'resources', 'gatekeeper_trees.json'))
 
 class GatekeeperTestApi(recipe_test_api.RecipeTestApi):
   def fake_test_data(self, data=None):
diff --git a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/basic.json b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/basic.json
index d6fe805..27a80fa 100644
--- a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/basic.json
+++ b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/basic.json
@@ -50,14 +50,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -67,14 +62,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
diff --git a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_by_url.json b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_by_url.json
index 3e5fc0b..3673676 100644
--- a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_by_url.json
+++ b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_by_url.json
@@ -52,14 +52,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "{}",
       "--service-account-path",
diff --git a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_infra_side.json b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_infra_side.json
index 4096a7f..a6f8bc8 100644
--- a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_infra_side.json
+++ b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/json_infra_side.json
@@ -34,14 +34,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/foobar/tree_closers.json",
       "--service-account-path",
diff --git a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/keep_going.json b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/keep_going.json
index 15da9ea..d1e476e 100644
--- a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/keep_going.json
+++ b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/keep_going.json
@@ -50,14 +50,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -71,14 +66,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
diff --git a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/kitchen.json b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/kitchen.json
index c0b3d9e..172e4f0 100644
--- a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/kitchen.json
+++ b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/kitchen.json
@@ -50,14 +50,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -67,14 +62,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
diff --git a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/production_data.json b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/production_data.json
index 845f224..f239239 100644
--- a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/production_data.json
+++ b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/production_data.json
@@ -262,14 +262,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -295,14 +290,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "{}",
       "--service-account-path",
@@ -331,14 +321,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "{}",
       "--service-account-path",
@@ -362,14 +347,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -390,14 +370,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -414,14 +389,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -432,14 +402,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -461,14 +426,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -481,14 +441,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -502,14 +457,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -531,14 +481,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -557,14 +502,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -577,14 +517,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -597,14 +532,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -633,14 +563,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
diff --git a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/whitelist_config.json b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/whitelist_config.json
index a2eb406..2cd9cfd 100644
--- a/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/whitelist_config.json
+++ b/scripts/slave/recipe_modules/gatekeeper/tests/call.expected/whitelist_config.json
@@ -51,14 +51,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
@@ -68,14 +63,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
       "--service-account-path",
diff --git a/scripts/slave/recipes/gatekeeper.expected/basic.json b/scripts/slave/recipes/gatekeeper.expected/basic.json
index c0b3d9e..003f497 100644
--- a/scripts/slave/recipes/gatekeeper.expected/basic.json
+++ b/scripts/slave/recipes/gatekeeper.expected/basic.json
@@ -4,7 +4,7 @@
       "python",
       "-u",
       "\nimport shutil\nimport sys\nshutil.copy(sys.argv[1], sys.argv[2])\n",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_trees.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_trees.json",
       "/path/to/tmp/json"
     ],
     "name": "reading gatekeeper_trees.json",
@@ -50,16 +50,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json"
     ],
@@ -67,16 +62,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
diff --git a/scripts/slave/recipes/gatekeeper.expected/keep_going.json b/scripts/slave/recipes/gatekeeper.expected/keep_going.json
index a0e6859..8b5e151 100644
--- a/scripts/slave/recipes/gatekeeper.expected/keep_going.json
+++ b/scripts/slave/recipes/gatekeeper.expected/keep_going.json
@@ -4,7 +4,7 @@
       "python",
       "-u",
       "\nimport shutil\nimport sys\nshutil.copy(sys.argv[1], sys.argv[2])\n",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_trees.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_trees.json",
       "/path/to/tmp/json"
     ],
     "name": "reading gatekeeper_trees.json",
@@ -50,16 +50,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json"
     ],
@@ -71,16 +66,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
diff --git a/scripts/slave/recipes/gatekeeper.expected/production_data.json b/scripts/slave/recipes/gatekeeper.expected/production_data.json
index 6d9e803..fb36bf0 100644
--- a/scripts/slave/recipes/gatekeeper.expected/production_data.json
+++ b/scripts/slave/recipes/gatekeeper.expected/production_data.json
@@ -4,7 +4,7 @@
       "python",
       "-u",
       "\nimport shutil\nimport sys\nshutil.copy(sys.argv[1], sys.argv[2])\n",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_trees.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_trees.json",
       "/path/to/tmp/json"
     ],
     "name": "reading gatekeeper_trees.json",
@@ -262,16 +262,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "https://build.chromium.org/p/chromiumos",
@@ -295,14 +290,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "{}",
       "--service-account-path",
@@ -331,14 +321,9 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
       "{}",
       "--service-account-path",
@@ -362,16 +347,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
@@ -390,16 +370,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--filter-domain",
@@ -414,16 +389,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "https://build.chromium.org/p/chromium.perf"
@@ -432,16 +402,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
@@ -461,16 +426,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--build-db",
@@ -481,16 +441,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--track-revisions",
@@ -502,16 +457,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
@@ -531,16 +481,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
@@ -557,16 +502,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--build-db",
@@ -577,16 +517,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "https://build.chromium.org/p/chromium:Android",
@@ -597,16 +532,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
@@ -633,16 +563,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
diff --git a/scripts/slave/recipes/gatekeeper.expected/whitelist_config.json b/scripts/slave/recipes/gatekeeper.expected/whitelist_config.json
index 8085637..cd77540 100644
--- a/scripts/slave/recipes/gatekeeper.expected/whitelist_config.json
+++ b/scripts/slave/recipes/gatekeeper.expected/whitelist_config.json
@@ -4,7 +4,7 @@
       "python",
       "-u",
       "\nimport shutil\nimport sys\nshutil.copy(sys.argv[1], sys.argv[2])\n",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_trees.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_trees.json",
       "/path/to/tmp/json"
     ],
     "name": "reading gatekeeper_trees.json",
@@ -51,16 +51,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json"
     ],
@@ -68,16 +63,11 @@
   },
   {
     "cmd": [
-      "python",
+      "vpython",
       "-u",
-      "RECIPE_REPO[build]/scripts/tools/runit.py",
-      "--show-path",
-      "--with-third-party-lib",
-      "--",
-      "python",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper_ng.py",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper_ng.py",
       "--json",
-      "RECIPE_REPO[build]/scripts/slave/gatekeeper.json",
+      "RECIPE_MODULE[build::gatekeeper]/resources/gatekeeper.json",
       "--service-account-path",
       "/creds/service_accounts/service-account-gatekeeper.json",
       "--status-url",
diff --git a/scripts/slave/recipes/gatekeeper.py b/scripts/slave/recipes/gatekeeper.py
index c2ca0d2..57f383b 100644
--- a/scripts/slave/recipes/gatekeeper.py
+++ b/scripts/slave/recipes/gatekeeper.py
@@ -18,8 +18,8 @@
   api.gatekeeper.c.use_new_logic = True
 
   api.gatekeeper(
-    api.repo_resource('scripts', 'slave', 'gatekeeper.json'),
-    api.repo_resource('scripts', 'slave', 'gatekeeper_trees.json'),
+    api.gatekeeper.resource('gatekeeper.json'),
+    api.gatekeeper.resource('gatekeeper_trees.json'),
   )