pyntcli 0.1.71__py3-none-any.whl → 0.1.73__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyntcli/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.71"
1
+ __version__ = "0.1.73"
@@ -0,0 +1,311 @@
1
+ import argparse
2
+ from copy import deepcopy
3
+ import os
4
+ import webbrowser
5
+ from http import HTTPStatus
6
+ import time
7
+ import tempfile
8
+ import json
9
+ from subprocess import Popen, PIPE
10
+ from functools import partial
11
+ import xmltodict
12
+ import base64
13
+ from xml.parsers.expat import ExpatError
14
+
15
+ from pyntcli.pynt_docker import pynt_container
16
+ from pyntcli.ui import ui_thread
17
+ from pyntcli.commands import util, sub_command
18
+ from pyntcli.ui import report as cli_reporter
19
+ from pyntcli.transport import pynt_requests
20
+
21
+ methods = [
22
+ "get",
23
+ "post",
24
+ "put",
25
+ "delete",
26
+ "patch",
27
+ "options",
28
+ "head",
29
+ "trace",
30
+ "connect",
31
+ ]
32
+
33
+
34
+ def is_valid_method(method: str):
35
+ if method.lower() in methods:
36
+ return True
37
+ return False
38
+
39
+
40
+ def replay_req(item, proxy_port):
41
+ url = item["url"]
42
+ decoded_req = base64.b64decode(item["request"]["#text"]).decode("utf-8")
43
+ method = decoded_req.split("\r\n")[0].split(" ")[0]
44
+
45
+ if not is_valid_method(method):
46
+ return
47
+
48
+ lines = decoded_req.split("\r\n")
49
+ if len(lines) < 2:
50
+ return
51
+
52
+ headers = {}
53
+
54
+ for line in lines[1:]:
55
+ if not line:
56
+ break
57
+
58
+ if ": " not in line:
59
+ break
60
+
61
+ key, value = line.split(": ")
62
+ headers[key] = value
63
+
64
+ body = decoded_req.split("\r\n\r\n")[1]
65
+ pynt_requests.request_from_xml(
66
+ method=method,
67
+ url=url,
68
+ headers=headers,
69
+ data=body,
70
+ proxies={
71
+ "http": "0.0.0.0:{}".format(proxy_port),
72
+ "https": "0.0.0.0:{}".format(proxy_port),
73
+ },
74
+ )
75
+
76
+
77
+ def run_burp_xml(doc, proxy_port):
78
+ items = doc["items"]["item"]
79
+ if isinstance(items, dict):
80
+ replay_req(item=items, proxy_port=proxy_port)
81
+ else:
82
+ [replay_req(i, proxy_port=proxy_port) for i in doc["items"]["item"]]
83
+
84
+
85
+ def parse_xml(xml_path):
86
+ try:
87
+ with open(xml_path) as fd:
88
+ return xmltodict.parse(fd.read())
89
+ except ExpatError:
90
+ return None
91
+
92
+
93
+ def is_valid_xml(doc) -> bool:
94
+ return "items" in doc
95
+
96
+
97
+ def burp_usage():
98
+ return (
99
+ ui_thread.PrinterText(
100
+ "Burp integration to Pynt. Run a security scan with a given burp xml output file."
101
+ )
102
+ .with_line("")
103
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER)
104
+ .with_line("\tpynt burp [OPTIONS]")
105
+ .with_line("")
106
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER)
107
+ .with_line("\t--xml - Path to the xml to run tests on")
108
+ .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)")
109
+ .with_line("\t--ca-path - The path to the CA file in PEM format")
110
+ .with_line(
111
+ "\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)"
112
+ )
113
+ .with_line(
114
+ "\t--report - If present will save the generated report in this path."
115
+ )
116
+ .with_line("\t--insecure - Use when target uses self signed certificates")
117
+ .with_line(
118
+ "\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
119
+ )
120
+ .with_line(
121
+ "\t--host-ca - Path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
122
+ )
123
+ .with_line(
124
+ "\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), "
125
+ )
126
+ )
127
+
128
+
129
+ class BurpCommand(sub_command.PyntSubCommand):
130
+ def __init__(self, name) -> None:
131
+ super().__init__(name)
132
+ self.scan_id = ""
133
+ self.proxy_sleep_interval = 2
134
+ self.proxy_healthcheck_buffer = 10
135
+ self.proxy_server_base_url = "http://localhost:{}/api"
136
+
137
+ def print_usage(self, *args):
138
+ ui_thread.print(burp_usage())
139
+
140
+ def add_cmd(self, parent: argparse._SubParsersAction) -> argparse.ArgumentParser:
141
+ burp_cmd = parent.add_parser(self.name)
142
+ burp_cmd.add_argument("--port", "-p", help="", type=int, default=5001)
143
+ burp_cmd.add_argument("--proxy-port", help="", type=int, default=6666)
144
+ burp_cmd.add_argument("--xml", help="", default="", required=True)
145
+ burp_cmd.add_argument("--ca-path", type=str, default="")
146
+ burp_cmd.add_argument("--report", type=str, default="")
147
+ burp_cmd.add_argument(
148
+ "--return-error",
149
+ choices=["all-findings", "errors-only", "never"],
150
+ default="never",
151
+ )
152
+ burp_cmd.print_usage = self.print_usage
153
+ burp_cmd.print_help = self.print_usage
154
+ return burp_cmd
155
+
156
+ def _updated_environment(self, args):
157
+ env_copy = deepcopy(os.environ)
158
+ return env_copy.update(
159
+ {
160
+ "HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
161
+ "HTTPS_PROXY": "http://localhost:{}".format(args.proxy_port),
162
+ }
163
+ )
164
+
165
+ def _start_proxy(self, args):
166
+ res = pynt_requests.put(
167
+ self.proxy_server_base_url.format(args.port) + "/proxy/start"
168
+ )
169
+ res.raise_for_status()
170
+ self.scan_id = res.json()["scanId"]
171
+
172
+ def _stop_proxy(self, args):
173
+ start = time.time()
174
+ while start + self.proxy_healthcheck_buffer > time.time():
175
+ res = pynt_requests.put(
176
+ self.proxy_server_base_url.format(args.port) + "/proxy/stop",
177
+ json={"scanId": self.scan_id},
178
+ )
179
+ if res.status_code == HTTPStatus.OK:
180
+ return
181
+ time.sleep(self.proxy_sleep_interval)
182
+ raise TimeoutError()
183
+
184
+ def _get_report(self, args, report_format):
185
+ while True:
186
+ res = pynt_requests.get(
187
+ self.proxy_server_base_url.format(args.port)
188
+ + "/report?format={}".format(report_format),
189
+ params={"scanId": self.scan_id},
190
+ )
191
+ if res.status_code == HTTPStatus.OK:
192
+ return res.text
193
+ if res.status_code == HTTPStatus.ACCEPTED:
194
+ time.sleep(self.proxy_sleep_interval)
195
+ continue
196
+ if res.status_code == 517: # pynt did not recieve any requests
197
+ ui_thread.print(
198
+ ui_thread.PrinterText(
199
+ res.json()["message"], ui_thread.PrinterText.WARNING
200
+ )
201
+ )
202
+ return
203
+ ui_thread.print("Error in polling for scan report: {}".format(res.text))
204
+ return
205
+
206
+ def run_cmd(self, args: argparse.Namespace):
207
+ container = pynt_container.get_container_with_arguments(
208
+ args,
209
+ pynt_container.PyntDockerPort(args.port, args.port, "--port"),
210
+ pynt_container.PyntDockerPort(
211
+ args.proxy_port, args.proxy_port, "--proxy-port"
212
+ ),
213
+ )
214
+ if "ca_path" in args and args.ca_path:
215
+ if not os.path.isfile(args.ca_path):
216
+ ui_thread.print(
217
+ ui_thread.PrinterText(
218
+ "Could not find the provided ca path, please provide with a valid path",
219
+ ui_thread.PrinterText.WARNING,
220
+ )
221
+ )
222
+ return
223
+
224
+ ca_name = os.path.basename(args.ca_path)
225
+ container.docker_arguments += ["--ca-path", ca_name]
226
+ container.mounts.append(
227
+ pynt_container.create_mount(
228
+ os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
229
+ )
230
+ )
231
+
232
+ if not os.path.isfile(args.xml):
233
+ ui_thread.print(
234
+ ui_thread.PrinterText(
235
+ "Could not find the provided xml path, please provide with a valid xml path",
236
+ ui_thread.PrinterText.WARNING,
237
+ )
238
+ )
239
+ return
240
+
241
+ doc = parse_xml(args.xml)
242
+ if not doc:
243
+ ui_thread.print(
244
+ ui_thread.PrinterText(
245
+ "Invalid file format. please provide a valid xml",
246
+ ui_thread.PrinterText.WARNING,
247
+ )
248
+ )
249
+ return
250
+
251
+ if not is_valid_xml(doc):
252
+ ui_thread.print(
253
+ ui_thread.PrinterText(
254
+ "Invalid xml file. please provide a valid xml output generated from burp",
255
+ ui_thread.PrinterText.WARNING,
256
+ )
257
+ )
258
+ return
259
+
260
+ proxy_docker = pynt_container.PyntContainer(
261
+ image_name=pynt_container.PYNT_DOCKER_IMAGE,
262
+ tag="proxy-latest",
263
+ detach=True,
264
+ base_container=container,
265
+ )
266
+ proxy_docker.run()
267
+ ui_thread.print_generator(proxy_docker.stdout)
268
+
269
+ util.wait_for_healthcheck("http://localhost:{}".format(args.port))
270
+ self._start_proxy(args)
271
+
272
+ run_burp_xml(doc, args.proxy_port)
273
+
274
+ self._stop_proxy(args)
275
+
276
+ with ui_thread.progress(
277
+ "ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),
278
+ partial(lambda *args: None),
279
+ "scan in progress...",
280
+ 100,
281
+ ):
282
+ html_report = self._get_report(args, "html")
283
+ html_report_path = os.path.join(
284
+ tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time()))
285
+ )
286
+
287
+ json_report = self._get_report(args, "json")
288
+ json_report_path = os.path.join(
289
+ tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time()))
290
+ )
291
+
292
+ if "report" in args and args.report:
293
+ full_path = os.path.abspath(args.report)
294
+ html_report_path = util.get_user_report_path(full_path, "html")
295
+ json_report_path = util.get_user_report_path(full_path, "json")
296
+
297
+ if html_report:
298
+ with open(html_report_path, "w") as html_file:
299
+ html_file.write(html_report)
300
+ webbrowser.open("file://{}".format(html_report_path))
301
+
302
+ if json_report:
303
+ with open(json_report_path, "w") as json_file:
304
+ json_file.write(json_report)
305
+ reporter = cli_reporter.PyntReporter(json_report_path)
306
+ reporter.print_summary()
307
+
308
+ if json_report:
309
+ json_obj = json.loads(json_report)
310
+ if json_obj:
311
+ util.check_for_findings_or_warnings(args, json_obj)
@@ -16,127 +16,219 @@ from pyntcli.ui import report as cli_reporter
16
16
  from pyntcli.transport import pynt_requests
17
17
 
18
18
 
19
-
20
19
  def command_usage():
21
- return ui_thread.PrinterText("Command integration to Pynt. Run a security scan with a given command.") \
22
- .with_line("") \
23
- .with_line("Usage:",style=ui_thread.PrinterText.HEADER) \
24
- .with_line("\tpynt command [OPTIONS]") \
25
- .with_line("") \
26
- .with_line("Options:",style=ui_thread.PrinterText.HEADER) \
27
- .with_line("\t--cmd - The command that runs the functional tests") \
28
- .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)") \
29
- .with_line("\t--allow-errors - If present will allow command to fail and continue execution") \
30
- .with_line("\t--ca-path - The path to the CA file in PEM format") \
31
- .with_line("\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)") \
32
- .with_line("\t--report - If present will save the generated report in this path.") \
33
- .with_line("\t--insecure - use when target uses self signed certificates") \
34
- .with_line("\t--host-ca - path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN.") \
35
- .with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), ")
36
-
37
-
38
- class CommandSubCommand(sub_command.PyntSubCommand):
20
+ return (
21
+ ui_thread.PrinterText(
22
+ "Command integration to Pynt. Run a security scan with a given command."
23
+ )
24
+ .with_line("")
25
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER)
26
+ .with_line("\tpynt command [OPTIONS]")
27
+ .with_line("")
28
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER)
29
+ .with_line("\t--cmd - The command that runs the functional tests")
30
+ .with_line(
31
+ '\t--captured-domains - Pynt will scan only these domains and subdomains. For all domains write "*"'
32
+ )
33
+ .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)")
34
+ .with_line(
35
+ "\t--allow-errors - If present will allow command to fail and continue execution"
36
+ )
37
+ .with_line("\t--ca-path - The path to the CA file in PEM format")
38
+ .with_line(
39
+ "\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)"
40
+ )
41
+ .with_line(
42
+ "\t--report - If present will save the generated report in this path."
43
+ )
44
+ .with_line("\t--insecure - Use when target uses self signed certificates")
45
+ .with_line(
46
+ "\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
47
+ )
48
+ .with_line(
49
+ "\t--host-ca - Path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
50
+ )
51
+ .with_line(
52
+ "\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), "
53
+ )
54
+ )
55
+
56
+
57
+ class CommandSubCommand(sub_command.PyntSubCommand):
39
58
  def __init__(self, name) -> None:
40
59
  super().__init__(name)
41
60
  self.scan_id = ""
42
61
  self.proxy_sleep_interval = 2
43
62
  self.proxy_healthcheck_buffer = 10
44
63
  self.proxy_server_base_url = "http://localhost:{}/api"
45
-
64
+
46
65
  def print_usage(self, *args):
47
66
  ui_thread.print(command_usage())
48
67
 
49
68
  def add_cmd(self, parent: argparse._SubParsersAction) -> argparse.ArgumentParser:
50
69
  proxy_cmd = parent.add_parser(self.name)
51
70
  proxy_cmd.add_argument("--port", "-p", help="", type=int, default=5001)
52
- proxy_cmd.add_argument("--proxy-port", help="", type=int, default=6666)
71
+ proxy_cmd.add_argument("--proxy-port", help="", type=int, default=6666)
53
72
  proxy_cmd.add_argument("--cmd", help="", default="", required=True)
73
+ proxy_cmd.add_argument(
74
+ "--captured-domains", nargs="+", help="", default="", required=False
75
+ )
54
76
  proxy_cmd.add_argument("--allow-errors", action="store_true")
55
77
  proxy_cmd.add_argument("--ca-path", type=str, default="")
56
78
  proxy_cmd.add_argument("--report", type=str, default="")
57
- proxy_cmd.add_argument('--return-error', choices=['all-findings', 'errors-only', 'never'], default='never')
79
+ proxy_cmd.add_argument(
80
+ "--return-error",
81
+ choices=["all-findings", "errors-only", "never"],
82
+ default="never",
83
+ )
58
84
  proxy_cmd.print_usage = self.print_usage
59
85
  proxy_cmd.print_help = self.print_usage
60
86
  return proxy_cmd
61
-
87
+
62
88
  def _updated_environment(self, args):
63
89
  env_copy = deepcopy(os.environ)
64
- return env_copy.update({"HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
65
- "HTTPS_PROXY": "http://localhost:{}".format(args.proxy_port)})
66
-
90
+ return env_copy.update(
91
+ {
92
+ "HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
93
+ "HTTPS_PROXY": "http://localhost:{}".format(args.proxy_port),
94
+ }
95
+ )
96
+
67
97
  def _start_proxy(self, args):
68
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/start")
98
+ res = pynt_requests.put(
99
+ self.proxy_server_base_url.format(args.port) + "/proxy/start"
100
+ )
69
101
  res.raise_for_status()
70
102
  self.scan_id = res.json()["scanId"]
71
-
103
+
72
104
  def _stop_proxy(self, args):
73
105
  start = time.time()
74
- while start + self.proxy_healthcheck_buffer > time.time():
75
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/stop", json={"scanId": self.scan_id})
76
- if res.status_code == HTTPStatus.OK:
77
- return
106
+ while start + self.proxy_healthcheck_buffer > time.time():
107
+ res = pynt_requests.put(
108
+ self.proxy_server_base_url.format(args.port) + "/proxy/stop",
109
+ json={"scanId": self.scan_id},
110
+ )
111
+ if res.status_code == HTTPStatus.OK:
112
+ return
78
113
  time.sleep(self.proxy_sleep_interval)
79
114
  raise TimeoutError()
80
-
81
- def _get_report(self, args,report_format):
82
- while True:
83
- res = pynt_requests.get(self.proxy_server_base_url.format(args.port) + "/report?format={}".format(report_format), params={"scanId": self.scan_id})
115
+
116
+ def _get_report(self, args, report_format):
117
+ while True:
118
+ res = pynt_requests.get(
119
+ self.proxy_server_base_url.format(args.port)
120
+ + "/report?format={}".format(report_format),
121
+ params={"scanId": self.scan_id},
122
+ )
84
123
  if res.status_code == HTTPStatus.OK:
85
124
  return res.text
86
125
  if res.status_code == HTTPStatus.ACCEPTED:
87
126
  time.sleep(self.proxy_sleep_interval)
88
127
  continue
89
- if res.status_code == 517: #pynt did not recieve any requests
90
- ui_thread.print(ui_thread.PrinterText(res.json()["message"], ui_thread.PrinterText.WARNING))
91
- return
128
+ if res.status_code == 517: # pynt did not recieve any requests
129
+ ui_thread.print(
130
+ ui_thread.PrinterText(
131
+ res.json()["message"], ui_thread.PrinterText.WARNING
132
+ )
133
+ )
134
+ return
92
135
  ui_thread.print("Error in polling for scan report: {}".format(res.text))
93
- return
136
+ return
94
137
 
95
-
96
138
  def run_cmd(self, args: argparse.Namespace):
97
- container = pynt_container.get_container_with_arguments(args, pynt_container.PyntDockerPort(args.port, args.port, "--port"),
98
- pynt_container.PyntDockerPort(args.proxy_port, args.proxy_port, "--proxy-port"))
139
+ container = pynt_container.get_container_with_arguments(
140
+ args,
141
+ pynt_container.PyntDockerPort(args.port, args.port, "--port"),
142
+ pynt_container.PyntDockerPort(
143
+ args.proxy_port, args.proxy_port, "--proxy-port"
144
+ ),
145
+ )
146
+
147
+ if args.captured_domains:
148
+ for host in args.captured_domains:
149
+ container.docker_arguments += ["--host-targets", host]
150
+
99
151
  if "ca_path" in args and args.ca_path:
100
152
  if not os.path.isfile(args.ca_path):
101
- ui_thread.print(ui_thread.PrinterText("Could not find the provided ca path, please provide with a valid path", ui_thread.PrinterText.WARNING))
153
+ ui_thread.print(
154
+ ui_thread.PrinterText(
155
+ "Could not find the provided ca path, please provide with a valid path",
156
+ ui_thread.PrinterText.WARNING,
157
+ )
158
+ )
102
159
  return
103
160
 
104
161
  ca_name = os.path.basename(args.ca_path)
105
162
  container.docker_arguments += ["--ca-path", ca_name]
106
- container.mounts.append(pynt_container.create_mount(os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)))
107
-
108
- proxy_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
109
- tag="proxy-latest",
110
- detach=True,
111
- base_container=container)
163
+ container.mounts.append(
164
+ pynt_container.create_mount(
165
+ os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
166
+ )
167
+ )
168
+
169
+ proxy_docker = pynt_container.PyntContainer(
170
+ image_name=pynt_container.PYNT_DOCKER_IMAGE,
171
+ tag="proxy-latest",
172
+ detach=True,
173
+ base_container=container,
174
+ )
112
175
  proxy_docker.run()
113
176
  ui_thread.print_generator(proxy_docker.stdout)
114
-
177
+
115
178
  util.wait_for_healthcheck("http://localhost:{}".format(args.port))
116
- self._start_proxy(args)
117
179
 
118
- user_process = Popen(args.cmd, shell=True, stdout=PIPE, stderr=PIPE, env=self._updated_environment(args))
180
+ if args.captured_domains:
181
+ ui_thread.print(
182
+ "\nWill scan APIs that belong to {} domains only".format(
183
+ args.captured_domains
184
+ )
185
+ )
186
+
187
+ self._start_proxy(args)
188
+
189
+ user_process = Popen(
190
+ args.cmd,
191
+ shell=True,
192
+ stdout=PIPE,
193
+ stderr=PIPE,
194
+ env=self._updated_environment(args),
195
+ )
119
196
  ui_thread.print_generator(user_process.stdout)
120
197
  ui_thread.print_generator(user_process.stderr)
121
198
  rc = user_process.wait()
122
199
  if rc != 0 and not args.allow_errors:
123
200
  proxy_docker.stop()
124
- ui_thread.print(ui_thread.PrinterText("Command finished with error return code {}, If you wish Pynt to run anyway, run with --allow-errors".format(rc)))
201
+ ui_thread.print(
202
+ ui_thread.PrinterText(
203
+ "Command finished with error return code {}, If you wish Pynt to run anyway, run with --allow-errors".format(
204
+ rc
205
+ )
206
+ )
207
+ )
125
208
  return
126
209
 
127
210
  self._stop_proxy(args)
128
-
129
- with ui_thread.progress("ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),partial(lambda *args: None), "scan in progress...", 100):
130
- html_report = self._get_report(args,"html")
131
- html_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time())))
132
211
 
133
- json_report = self._get_report(args,"json")
134
- json_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time())))
212
+ with ui_thread.progress(
213
+ "ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),
214
+ partial(lambda *args: None),
215
+ "scan in progress...",
216
+ 100,
217
+ ):
218
+ html_report = self._get_report(args, "html")
219
+ html_report_path = os.path.join(
220
+ tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time()))
221
+ )
222
+
223
+ json_report = self._get_report(args, "json")
224
+ json_report_path = os.path.join(
225
+ tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time()))
226
+ )
135
227
 
136
228
  if "report" in args and args.report:
137
229
  full_path = os.path.abspath(args.report)
138
- html_report_path = util.get_user_report_path(full_path,"html")
139
- json_report_path = util.get_user_report_path(full_path,"json")
230
+ html_report_path = util.get_user_report_path(full_path, "html")
231
+ json_report_path = util.get_user_report_path(full_path, "json")
140
232
 
141
233
  if html_report:
142
234
  with open(html_report_path, "w") as html_file:
@@ -153,4 +245,3 @@ class CommandSubCommand(sub_command.PyntSubCommand):
153
245
  json_obj = json.loads(json_report)
154
246
  if json_obj:
155
247
  util.check_for_findings_or_warnings(args, json_obj)
156
-