Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(557)

Side by Side Diff: gclient.py

Issue 562953002: Rough verification code to ensure deps hosts \in allowed_hosts. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Fixed docs + iannucci suggestions. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/gclient_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Meta checkout manager supporting both Subversion and GIT.""" 6 """Meta checkout manager supporting both Subversion and GIT."""
7 # Files 7 # Files
8 # .gclient : Current client configuration, written by 'config' command. 8 # .gclient : Current client configuration, written by 'config' command.
9 # Format is a Python script defining 'solutions', a list whose 9 # Format is a Python script defining 'solutions', a list whose
10 # entries each are maps binding the strings "name" and "url" 10 # entries each are maps binding the strings "name" and "url"
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 self._deps_hooks = [] 335 self._deps_hooks = []
336 336
337 self._pre_deps_hooks = [] 337 self._pre_deps_hooks = []
338 338
339 # Calculates properties: 339 # Calculates properties:
340 self._parsed_url = None 340 self._parsed_url = None
341 self._dependencies = [] 341 self._dependencies = []
342 # A cache of the files affected by the current operation, necessary for 342 # A cache of the files affected by the current operation, necessary for
343 # hooks. 343 # hooks.
344 self._file_list = [] 344 self._file_list = []
345 # List of host names from which dependencies are allowed.
346 # Default is an empty set, meaning unspecified in DEPS file, and hence all
347 # hosts will be allowed. Non-empty set means whitelist of hosts.
348 # allowed_hosts var is scoped to its DEPS file, and so it isn't recursive.
349 self._allowed_hosts = frozenset()
345 # If it is not set to True, the dependency wasn't processed for its child 350 # If it is not set to True, the dependency wasn't processed for its child
346 # dependency, i.e. its DEPS wasn't read. 351 # dependency, i.e. its DEPS wasn't read.
347 self._deps_parsed = False 352 self._deps_parsed = False
348 # This dependency has been processed, i.e. checked out 353 # This dependency has been processed, i.e. checked out
349 self._processed = False 354 self._processed = False
350 # This dependency had its pre-DEPS hooks run 355 # This dependency had its pre-DEPS hooks run
351 self._pre_deps_hooks_ran = False 356 self._pre_deps_hooks_ran = False
352 # This dependency had its hook run 357 # This dependency had its hook run
353 self._hooks_ran = False 358 self._hooks_ran = False
354 # This is the scm used to checkout self.url. It may be used by dependencies 359 # This is the scm used to checkout self.url. It may be used by dependencies
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
680 deps = rel_deps 685 deps = rel_deps
681 686
682 # Update recursedeps if it's set. 687 # Update recursedeps if it's set.
683 if self.recursedeps is not None: 688 if self.recursedeps is not None:
684 logging.warning('Updating recursedeps by prepending %s.', self.name) 689 logging.warning('Updating recursedeps by prepending %s.', self.name)
685 rel_deps = set() 690 rel_deps = set()
686 for d in self.recursedeps: 691 for d in self.recursedeps:
687 rel_deps.add(os.path.normpath(os.path.join(self.name, d))) 692 rel_deps.add(os.path.normpath(os.path.join(self.name, d)))
688 self.recursedeps = rel_deps 693 self.recursedeps = rel_deps
689 694
695 if 'allowed_hosts' in local_scope:
696 try:
697 self._allowed_hosts = frozenset(local_scope.get('allowed_hosts'))
698 except TypeError: # raised if non-iterable
699 pass
700 if not self._allowed_hosts:
701 logging.warning("allowed_hosts is specified but empty %s",
702 self._allowed_hosts)
703 raise gclient_utils.Error(
704 'ParseDepsFile(%s): allowed_hosts must be absent '
705 'or a non-empty iterable' % self.name)
706
690 # Convert the deps into real Dependency. 707 # Convert the deps into real Dependency.
691 deps_to_add = [] 708 deps_to_add = []
692 for name, url in deps.iteritems(): 709 for name, url in deps.iteritems():
693 should_process = self.recursion_limit and self.should_process 710 should_process = self.recursion_limit and self.should_process
694 deps_to_add.append(Dependency( 711 deps_to_add.append(Dependency(
695 self, name, url, None, None, None, None, None, 712 self, name, url, None, None, None, None, None,
696 self.deps_file, should_process)) 713 self.deps_file, should_process))
697 deps_to_add.sort(key=lambda x: x.name) 714 deps_to_add.sort(key=lambda x: x.name)
698 715
699 # override named sets of hooks by the custom hooks 716 # override named sets of hooks by the custom hooks
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 'repository.' % options.revision) 766 'repository.' % options.revision)
750 else: 767 else:
751 parent_revision_date = self.parent.used_scm.GetRevisionDate( 768 parent_revision_date = self.parent.used_scm.GetRevisionDate(
752 options.revision) 769 options.revision)
753 options.revision = gclient_utils.MakeDateRevision( 770 options.revision = gclient_utils.MakeDateRevision(
754 parent_revision_date) 771 parent_revision_date)
755 if options.verbose: 772 if options.verbose:
756 print('Using parent\'s revision date %s since we are in a ' 773 print('Using parent\'s revision date %s since we are in a '
757 'different repository.' % options.revision) 774 'different repository.' % options.revision)
758 775
776 def findDepsFromNotAllowedHosts(self):
777 """Returns a list of depenecies from not allowed hosts.
778
779 If allowed_hosts is not set, allows all hosts and returns empty list.
780 """
781 if not self._allowed_hosts:
782 return []
783 bad_deps = []
784 for dep in self._dependencies:
785 if isinstance(dep.url, basestring):
786 parsed_url = urlparse.urlparse(dep.url)
787 if parsed_url.netloc and parsed_url.netloc not in self._allowed_hosts:
788 bad_deps.append(dep)
789 return bad_deps
790
759 # Arguments number differs from overridden method 791 # Arguments number differs from overridden method
760 # pylint: disable=W0221 792 # pylint: disable=W0221
761 def run(self, revision_overrides, command, args, work_queue, options): 793 def run(self, revision_overrides, command, args, work_queue, options):
762 """Runs |command| then parse the DEPS file.""" 794 """Runs |command| then parse the DEPS file."""
763 logging.info('Dependency(%s).run()' % self.name) 795 logging.info('Dependency(%s).run()' % self.name)
764 assert self._file_list == [] 796 assert self._file_list == []
765 if not self.should_process: 797 if not self.should_process:
766 return 798 return
767 # When running runhooks, there's no need to consult the SCM. 799 # When running runhooks, there's no need to consult the SCM.
768 # All known hooks are expected to run unconditionally regardless of working 800 # All known hooks are expected to run unconditionally regardless of working
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
1046 def pre_deps_hooks_ran(self): 1078 def pre_deps_hooks_ran(self):
1047 return self._pre_deps_hooks_ran 1079 return self._pre_deps_hooks_ran
1048 1080
1049 @property 1081 @property
1050 @gclient_utils.lockedmethod 1082 @gclient_utils.lockedmethod
1051 def hooks_ran(self): 1083 def hooks_ran(self):
1052 return self._hooks_ran 1084 return self._hooks_ran
1053 1085
1054 @property 1086 @property
1055 @gclient_utils.lockedmethod 1087 @gclient_utils.lockedmethod
1088 def allowed_hosts(self):
1089 return self._allowed_hosts
1090
1091 @property
1092 @gclient_utils.lockedmethod
1056 def file_list(self): 1093 def file_list(self):
1057 return tuple(self._file_list) 1094 return tuple(self._file_list)
1058 1095
1059 @property 1096 @property
1060 def used_scm(self): 1097 def used_scm(self):
1061 """SCMWrapper instance for this dependency or None if not processed yet.""" 1098 """SCMWrapper instance for this dependency or None if not processed yet."""
1062 return self._used_scm 1099 return self._used_scm
1063 1100
1064 @property 1101 @property
1065 @gclient_utils.lockedmethod 1102 @gclient_utils.lockedmethod
1066 def got_revision(self): 1103 def got_revision(self):
1067 return self._got_revision 1104 return self._got_revision
1068 1105
1069 @property 1106 @property
1070 def file_list_and_children(self): 1107 def file_list_and_children(self):
1071 result = list(self.file_list) 1108 result = list(self.file_list)
1072 for d in self.dependencies: 1109 for d in self.dependencies:
1073 result.extend(d.file_list_and_children) 1110 result.extend(d.file_list_and_children)
1074 return tuple(result) 1111 return tuple(result)
1075 1112
1076 def __str__(self): 1113 def __str__(self):
1077 out = [] 1114 out = []
1078 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', 1115 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps',
1079 'custom_vars', 'deps_hooks', 'file_list', 'should_process', 1116 'custom_vars', 'deps_hooks', 'file_list', 'should_process',
1080 'processed', 'hooks_ran', 'deps_parsed', 'requirements'): 1117 'processed', 'hooks_ran', 'deps_parsed', 'requirements',
1118 'allowed_hosts'):
1081 # First try the native property if it exists. 1119 # First try the native property if it exists.
1082 if hasattr(self, '_' + i): 1120 if hasattr(self, '_' + i):
1083 value = getattr(self, '_' + i, False) 1121 value = getattr(self, '_' + i, False)
1084 else: 1122 else:
1085 value = getattr(self, i, False) 1123 value = getattr(self, i, False)
1086 if value: 1124 if value:
1087 out.append('%s: %s' % (i, value)) 1125 out.append('%s: %s' % (i, value))
1088 1126
1089 for d in self.dependencies: 1127 for d in self.dependencies:
1090 out.extend([' ' + x for x in str(d).splitlines()]) 1128 out.extend([' ' + x for x in str(d).splitlines()])
(...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after
2079 (options, args) = parser.parse_args(args) 2117 (options, args) = parser.parse_args(args)
2080 options.force = True 2118 options.force = True
2081 client = GClient.LoadCurrentConfig(options) 2119 client = GClient.LoadCurrentConfig(options)
2082 if not client: 2120 if not client:
2083 raise gclient_utils.Error('client not configured; see \'gclient config\'') 2121 raise gclient_utils.Error('client not configured; see \'gclient config\'')
2084 client.RunOnDeps(None, []) 2122 client.RunOnDeps(None, [])
2085 print '; '.join(' '.join(hook) for hook in client.GetHooks(options)) 2123 print '; '.join(' '.join(hook) for hook in client.GetHooks(options))
2086 return 0 2124 return 0
2087 2125
2088 2126
2127 def CMDverify(parser, args):
2128 """Verifies the DEPS file deps are only from allowed_hosts."""
2129 (options, args) = parser.parse_args(args)
2130 client = GClient.LoadCurrentConfig(options)
2131 if not client:
2132 raise gclient_utils.Error('client not configured; see \'gclient config\'')
2133 client.RunOnDeps(None, [])
2134 # Look at each first-level dependency of this gclient only.
2135 for dep in client.dependencies:
2136 bad_deps = dep.findDepsFromNotAllowedHosts()
2137 if not bad_deps:
2138 continue
2139 print "There are deps from not allowed hosts in file %s" % dep.deps_file
2140 for bad_dep in bad_deps:
2141 print "\t%s at %s" % (bad_dep.name, bad_dep.url)
2142 print "allowed_hosts:", ', '.join(dep.allowed_hosts)
2143 sys.stdout.flush()
2144 raise gclient_utils.Error(
2145 'dependencies from disallowed hosts; check your DEPS file.')
2146 return 0
2147
2089 class OptionParser(optparse.OptionParser): 2148 class OptionParser(optparse.OptionParser):
2090 gclientfile_default = os.environ.get('GCLIENT_FILE', '.gclient') 2149 gclientfile_default = os.environ.get('GCLIENT_FILE', '.gclient')
2091 2150
2092 def __init__(self, **kwargs): 2151 def __init__(self, **kwargs):
2093 optparse.OptionParser.__init__( 2152 optparse.OptionParser.__init__(
2094 self, version='%prog ' + __version__, **kwargs) 2153 self, version='%prog ' + __version__, **kwargs)
2095 2154
2096 # Some arm boards have issues with parallel sync. 2155 # Some arm boards have issues with parallel sync.
2097 if platform.machine().startswith('arm'): 2156 if platform.machine().startswith('arm'):
2098 jobs = 1 2157 jobs = 1
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
2194 print >> sys.stderr, 'Error: %s' % str(e) 2253 print >> sys.stderr, 'Error: %s' % str(e)
2195 return 1 2254 return 1
2196 finally: 2255 finally:
2197 gclient_utils.PrintWarnings() 2256 gclient_utils.PrintWarnings()
2198 2257
2199 2258
2200 if '__main__' == __name__: 2259 if '__main__' == __name__:
2201 sys.exit(Main(sys.argv[1:])) 2260 sys.exit(Main(sys.argv[1:]))
2202 2261
2203 # vim: ts=2:sw=2:tw=80:et: 2262 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | tests/gclient_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698