OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2015 The LUCI Authors. All rights reserved. | 2 # Copyright 2015 The LUCI Authors. All rights reserved. |
3 # Use of this source code is governed under the Apache License, Version 2.0 | 3 # Use of this source code is governed under the Apache License, Version 2.0 |
4 # that can be found in the LICENSE file. | 4 # that can be found in the LICENSE file. |
5 | 5 |
6 """Tests that recipes are on their best behavior. | 6 """Tests that recipes are on their best behavior. |
7 | 7 |
8 Checks that recipes only import modules from a whitelist. Imports are | 8 Checks that recipes only import modules from a whitelist. Imports are |
9 generally not safe in recipes if they depend on the platform, since | 9 generally not safe in recipes if they depend on the platform, since |
10 e.g. you can run a recipe simulation for a Windows recipe on Linux. | 10 e.g. you can run a recipe simulation for a Windows recipe on Linux. |
11 """ | 11 """ |
12 | 12 |
13 # TODO(luqui): Implement lint for recipe modules also. | 13 # TODO(luqui): Implement lint for recipe modules also. |
14 | 14 |
15 from __future__ import absolute_import | 15 from __future__ import absolute_import |
16 import re | 16 import re |
17 import types | 17 import types |
18 | 18 |
19 | 19 |
20 MODULES_WHITELIST = [ | 20 MODULES_WHITELIST = [ |
| 21 r'ast', |
21 r'base64', | 22 r'base64', |
22 r'collections', | 23 r'collections', |
23 r'contextlib', | 24 r'contextlib', |
24 r'copy', | 25 r'copy', |
25 r'datetime', | 26 r'datetime', |
26 r'functools', | 27 r'functools', |
27 r'hashlib', | 28 r'hashlib', |
28 r'itertools', | 29 r'itertools', |
29 r'json', | 30 r'json', |
30 r'math', | 31 r'math', |
31 r're', | 32 r're', |
32 r'urlparse', | 33 r'urlparse', |
33 r'zlib', | 34 r'zlib', |
34 ] | 35 ] |
35 | 36 |
36 | 37 |
37 class ImportViolationError(Exception): | |
38 pass | |
39 | |
40 | |
41 class TestFailure(Exception): | |
42 pass | |
43 | |
44 | |
45 def ImportsTest(recipe_path, recipe_name, whitelist, universe_view): | 38 def ImportsTest(recipe_path, recipe_name, whitelist, universe_view): |
46 """Tests that recipe_name only uses allowed imports. | 39 """Tests that recipe_name only uses allowed imports. |
47 | 40 |
48 Returns a list of errors, or an empty list if there are no errors (duh). | 41 Returns a list of errors, or an empty list if there are no errors (duh). |
49 """ | 42 """ |
50 | 43 |
51 recipe = universe_view.load_recipe(recipe_name) | 44 recipe = universe_view.load_recipe(recipe_name) |
52 for _, val in sorted(recipe.globals.iteritems()): | 45 for _, val in sorted(recipe.globals.iteritems()): |
53 if isinstance(val, types.ModuleType): | 46 if isinstance(val, types.ModuleType): |
54 module_name = val.__name__ | 47 module_name = val.__name__ |
(...skipping 27 matching lines...) Expand all Loading... |
82 universe_view = loader.UniverseView(universe, package_deps.root_package) | 75 universe_view = loader.UniverseView(universe, package_deps.root_package) |
83 | 76 |
84 whitelist = map(re.compile, MODULES_WHITELIST + args.whitelist) | 77 whitelist = map(re.compile, MODULES_WHITELIST + args.whitelist) |
85 | 78 |
86 errors = [] | 79 errors = [] |
87 for recipe_path, recipe_name in universe_view.loop_over_recipes(): | 80 for recipe_path, recipe_name in universe_view.loop_over_recipes(): |
88 errors.extend( | 81 errors.extend( |
89 ImportsTest(recipe_path, recipe_name, whitelist, universe_view)) | 82 ImportsTest(recipe_path, recipe_name, whitelist, universe_view)) |
90 | 83 |
91 if errors: | 84 if errors: |
92 raise TestFailure('\n'.join(map(str, errors))) | 85 for line in map(str, errors): |
| 86 print line |
| 87 return 1 |
| 88 return 0 |
OLD | NEW |