Bug 1610307 [wpt PR 21266] - Update wpt metadata, a=testonly
[gecko.git] / python / safety / mach_commands.py
blob4ea934891db805e600842b691e9901f93cad99b6
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 from __future__ import absolute_import, print_function, unicode_literals
7 import os
8 import sys
9 import json
11 from mozbuild.base import (
12 MachCommandBase,
15 from mach.decorators import (
16 CommandArgument,
17 CommandProvider,
18 Command,
21 import mozpack.path as mozpath
22 from mozpack.files import FileFinder
24 from mozlog import commandline
26 here = os.path.abspath(os.path.dirname(__file__))
29 @CommandProvider
30 class MachCommands(MachCommandBase):
31 @Command('python-safety', category='testing',
32 description='Run python requirements safety checks')
33 @CommandArgument('--python',
34 default='3.5',
35 help='Version of Python for Pipenv to use. When given a '
36 'Python version, Pipenv will automatically scan your '
37 'system for a Python that matches that given version.')
38 def python_safety(self, python=None, **kwargs):
39 self.logger = commandline.setup_logging(
40 "python-safety", {"raw": sys.stdout})
42 self.activate_pipenv(pipfile=os.path.join(here, 'Pipfile'), python=python, populate=True)
44 pattern = '**/*requirements*.txt'
45 path = mozpath.normsep(os.path.dirname(os.path.dirname(here)))
46 finder = FileFinder(path)
47 files = [os.path.join(path, p) for p, _ in finder.find(pattern)]
49 return_code = 0
51 self.logger.suite_start(tests=files)
52 for filepath in files:
53 self._run_python_safety(filepath)
55 self.logger.suite_end()
56 return return_code
58 def _run_python_safety(self, test_path):
59 from mozprocess import ProcessHandler
61 output = []
62 self.logger.test_start(test_path)
64 def _line_handler(line):
65 output.append(line.decode('UTF-8'))
67 cmd = ['safety', 'check', '--cache', '--json', '-r', test_path]
68 env = os.environ.copy()
69 env['PYTHONDONTWRITEBYTECODE'] = '1'
71 proc = ProcessHandler(
72 cmd, env=env, processOutputLine=_line_handler, storeOutput=False)
73 proc.run()
75 return_code = proc.wait()
77 """
78 Example output for an error in json.
80 "pycrypto",
81 "<=2.6.1",
82 "2.6",
83 "Heap-based buffer overflow in the ALGnew...",
84 "35015"
86 """
87 # Warnings are currently interleaved with json, see
88 # https://github.com/pyupio/safety/issues/133
89 for warning in output:
90 if warning.startswith('Warning'):
91 self.logger.warning(warning)
92 output = [line for line in output if not line.startswith('Warning')]
93 if output:
94 output_json = json.loads("".join(output))
95 affected = set()
96 for entry in output_json:
97 affected.add(entry[0])
98 message = "{0} installed:{2} affected:{1} description:{3}\n".format(
99 *entry)
100 self.logger.test_status(test=test_path,
101 subtest=entry[0],
102 status='FAIL',
103 message=message
106 if return_code != 0:
107 status = 'FAIL'
108 else:
109 status = 'PASS'
110 self.logger.test_end(test_path, status=status,
111 expected='PASS', message=" ".join(affected))
113 return return_code