Chromium Code Reviews| Index: gclient.py |
| diff --git a/gclient.py b/gclient.py |
| index 3007487a5930d0f09aeac1260defe3be12bd4360..1c1eeee4360daf7944baac51cbc9a4c9de055285 100755 |
| --- a/gclient.py |
| +++ b/gclient.py |
| @@ -342,6 +342,11 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): |
| # A cache of the files affected by the current operation, necessary for |
| # hooks. |
| self._file_list = [] |
| + # List of host names from which from which dependencies are allowed. |
| + # Default is an empty set, meaning unspecified in DEPS file, and hence |
| + # all are hosts will be allowed. Non-empty set means whitelist of hosts. |
| + # allowed_hosts var is scoped to its DEPS file, and so it isn't recurisve. |
| + self._allowed_hosts = set() |
|
iannucci
2014/09/18 20:54:40
make it an empty frozenset
tandrii(chromium)
2014/09/18 21:45:58
Done.
|
| # If it is not set to True, the dependency wasn't processed for its child |
| # dependency, i.e. its DEPS wasn't read. |
| self._deps_parsed = False |
| @@ -687,6 +692,15 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): |
| rel_deps.add(os.path.normpath(os.path.join(self.name, d))) |
| self.recursedeps = rel_deps |
| + if 'allowed_hosts' in local_scope: |
| + self._allowed_hosts = set(local_scope.get('allowed_hosts')) |
|
iannucci
2014/09/18 20:54:41
this could throw a TypeError if it's a non-iterabl
tandrii(chromium)
2014/09/18 21:45:58
Done.
|
| + if not self._allowed_hosts: |
| + logging.warning("allowed_hosts is specified but empty %s", |
| + self._allowed_hosts) |
| + raise gclient_utils.Error( |
| + 'ParseDepsFile(%s): allowed_hosts must be a non-empty iterable' % |
|
iannucci
2014/09/18 20:54:40
may want to tell them to delete it if they're maki
tandrii(chromium)
2014/09/18 21:45:58
Done.
|
| + self.name) |
| + |
| # Convert the deps into real Dependency. |
| deps_to_add = [] |
| for name, url in deps.iteritems(): |
| @@ -756,6 +770,21 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): |
| print('Using parent\'s revision date %s since we are in a ' |
| 'different repository.' % options.revision) |
| + def findDepsFromNotAllowedHosts(self): |
| + """Returns a list of depenecies from not allowed hosts. |
| + |
| + If allowed_hosts is not set, allows all hosts and returns empty list. |
| + """ |
| + if self._allowed_hosts is None: |
| + return [] |
| + bad_deps = [] |
| + for dep in self._dependencies: |
| + if isinstance(dep.url, basestring): |
| + parsed_url = urlparse.urlparse(dep.url) |
| + if parsed_url.netloc and parsed_url.netloc not in self._allowed_hosts: |
| + bad_deps.append(dep) |
| + return bad_deps |
| + |
| # Arguments number differs from overridden method |
| # pylint: disable=W0221 |
| def run(self, revision_overrides, command, args, work_queue, options): |
| @@ -1053,6 +1082,11 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): |
| @property |
| @gclient_utils.lockedmethod |
| + def allowed_hosts(self): |
| + return frozenset(self._allowed_hosts) |
|
iannucci
2014/09/18 20:54:40
can return a reference since it's an immutable typ
tandrii(chromium)
2014/09/18 21:45:58
Done.
|
| + |
| + @property |
| + @gclient_utils.lockedmethod |
| def file_list(self): |
| return tuple(self._file_list) |
| @@ -1077,7 +1111,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): |
| out = [] |
| for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', |
| 'custom_vars', 'deps_hooks', 'file_list', 'should_process', |
| - 'processed', 'hooks_ran', 'deps_parsed', 'requirements'): |
| + 'processed', 'hooks_ran', 'deps_parsed', 'requirements', |
| + 'allowed_hosts'): |
| # First try the native property if it exists. |
| if hasattr(self, '_' + i): |
| value = getattr(self, '_' + i, False) |
| @@ -2086,6 +2121,27 @@ def CMDhookinfo(parser, args): |
| return 0 |
| +def CMDverify(parser, args): |
| + """Verifies the DEPS file deps are only from allowed_hosts.""" |
| + (options, args) = parser.parse_args(args) |
| + client = GClient.LoadCurrentConfig(options) |
| + if not client: |
| + raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| + client.RunOnDeps(None, []) |
| + # Look at each first-level dependency of this gclient only. |
| + for dep in client.dependencies: |
| + bad_deps = dep.findDepsFromNotAllowedHosts() |
| + if not bad_deps: |
| + continue |
| + print "There are deps from not allowed hosts in file %s" % dep.deps_file |
| + for bad_dep in bad_deps: |
| + print "\t%s at %s" % (bad_dep.name, bad_dep.url) |
| + print "allowed_hosts:", ', '.join(dep.allowed_hosts) |
| + sys.stdout.flush() |
| + raise gclient_utils.Error( |
| + 'dependencies from disallowed hosts; check your DEPS file.') |
| + return 0 |
| + |
| class OptionParser(optparse.OptionParser): |
| gclientfile_default = os.environ.get('GCLIENT_FILE', '.gclient') |