pyntcli 0.1.114__py3-none-any.whl → 0.1.116__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 +1 -1
- pyntcli/commands/burp.py +1 -0
- pyntcli/commands/command.py +2 -0
- pyntcli/commands/har.py +1 -0
- pyntcli/commands/listen.py +1 -0
- pyntcli/commands/newman.py +3 -0
- pyntcli/commands/pynt_cmd.py +39 -25
- pyntcli/commands/root.py +2 -0
- pyntcli/pynt_docker/pynt_container.py +42 -26
- pyntcli/saas_client/__init__.py +1 -0
- pyntcli/saas_client/saas_client.py +56 -0
- pyntcli/ui/pynt_errors.py +3 -5
- {pyntcli-0.1.114.dist-info → pyntcli-0.1.116.dist-info}/METADATA +2 -2
- {pyntcli-0.1.114.dist-info → pyntcli-0.1.116.dist-info}/RECORD +18 -16
- {pyntcli-0.1.114.dist-info → pyntcli-0.1.116.dist-info}/WHEEL +1 -1
- tests/commands/test_pynt_cmd.py +31 -22
- {pyntcli-0.1.114.dist-info → pyntcli-0.1.116.dist-info}/entry_points.txt +0 -0
- {pyntcli-0.1.114.dist-info → pyntcli-0.1.116.dist-info}/top_level.txt +0 -0
pyntcli/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.116"
|
pyntcli/commands/burp.py
CHANGED
|
@@ -149,6 +149,7 @@ def burp_usage():
|
|
|
149
149
|
.with_line("\t--report - If present will save the generated report in this path.")
|
|
150
150
|
.with_line("\t--insecure - Use when target uses self signed certificates")
|
|
151
151
|
.with_line("\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io")
|
|
152
|
+
.with_line("\t--application-name - Attach the scan to an application, application will be created automatically if it does not exist.")
|
|
152
153
|
.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.")
|
|
153
154
|
.with_line("\t--severity-level - 'all', 'medium', 'high', 'critical', 'none' (default) ")
|
|
154
155
|
.with_line("\t--tag - Tag the scan. Repeat for multiple tags")
|
pyntcli/commands/command.py
CHANGED
|
@@ -38,6 +38,8 @@ def command_usage():
|
|
|
38
38
|
.with_line("\t--self-signed - Use when the functional test verify SSL")
|
|
39
39
|
.with_line("\t--no-proxy-export - Pynt will not export the proxy settings to the environment")
|
|
40
40
|
.with_line("\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io")
|
|
41
|
+
.with_line(
|
|
42
|
+
"\t--application-name - Attach the scan to an application, application will be created automatically if it does not exist.")
|
|
41
43
|
.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.")
|
|
42
44
|
.with_line("\t--severity-level - 'all', 'medium', 'high', 'critical', 'none' (default) ")
|
|
43
45
|
.with_line("\t--tag - Tag the scan. Repeat for multiple tags")
|
pyntcli/commands/har.py
CHANGED
|
@@ -25,6 +25,7 @@ def har_usage():
|
|
|
25
25
|
.with_line(
|
|
26
26
|
"\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
|
|
27
27
|
)
|
|
28
|
+
.with_line("\t--application-name - Attach the scan to an application, application will be created automatically if it does not exist.")
|
|
28
29
|
.with_line(
|
|
29
30
|
"\t--host-ca - Path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
|
|
30
31
|
)
|
pyntcli/commands/listen.py
CHANGED
|
@@ -31,6 +31,7 @@ def listen_usage():
|
|
|
31
31
|
.with_line("\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)")
|
|
32
32
|
.with_line("\t--report - If present will save the generated report in this path.")
|
|
33
33
|
.with_line("\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io")
|
|
34
|
+
.with_line("\t--application-name - Attach the scan to an application, application will be created automatically if it does not exist.")
|
|
34
35
|
.with_line("\t--insecure - use when target uses self signed certificates")
|
|
35
36
|
.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.")
|
|
36
37
|
.with_line("\t--severity-level - 'all', 'medium', 'high', 'critical', 'none' (default) ")
|
pyntcli/commands/newman.py
CHANGED
|
@@ -28,6 +28,9 @@ def newman_usage():
|
|
|
28
28
|
.with_line(
|
|
29
29
|
"\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
|
|
30
30
|
)
|
|
31
|
+
.with_line(
|
|
32
|
+
"\t--application-name - Attach the scan to an application, application will be created automatically if it does not exist."
|
|
33
|
+
)
|
|
31
34
|
.with_line("\t--severity-level - 'all', 'medium', 'high', 'critical', 'none' (default) ")
|
|
32
35
|
.with_line("\t--tag - Tag the scan. Repeat for multiple tags")
|
|
33
36
|
.with_line("\t--verbose - Use to get more detailed information about the run")
|
pyntcli/commands/pynt_cmd.py
CHANGED
|
@@ -7,8 +7,9 @@ from pyntcli.analytics import send as analytics
|
|
|
7
7
|
from pyntcli.transport import pynt_requests
|
|
8
8
|
from pyntcli.ui import ui_thread
|
|
9
9
|
from pyntcli.ui import prompt
|
|
10
|
-
from pyntcli.store import
|
|
10
|
+
from pyntcli.store import StateStore
|
|
11
11
|
import pyntcli.log.log as log
|
|
12
|
+
from pyntcli.saas_client.saas_client import pynt_client
|
|
12
13
|
|
|
13
14
|
from requests.exceptions import SSLError, HTTPError
|
|
14
15
|
|
|
@@ -123,25 +124,30 @@ class PyntCommand:
|
|
|
123
124
|
Returns:
|
|
124
125
|
bool: True if it's a business-plan user
|
|
125
126
|
"""
|
|
126
|
-
saas_url = "https://api.pynt.io/v1/config"
|
|
127
|
-
headers = {}
|
|
128
|
-
with CredStore() as store:
|
|
129
|
-
access_keys = store.get_access_token()
|
|
130
|
-
token_type = store.get_token_type()
|
|
131
|
-
headers["Authorization"] = f"{token_type} {access_keys}"
|
|
132
127
|
try:
|
|
133
|
-
response = requests.get(saas_url, headers=headers, timeout=10)
|
|
134
128
|
|
|
135
|
-
if
|
|
129
|
+
if pynt_client.get_config():
|
|
136
130
|
return True
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
except
|
|
140
|
-
# Catch all other request exceptions
|
|
141
|
-
logger.debug(f"An error occurred when accessing '{saas_url}': {e}")
|
|
131
|
+
|
|
132
|
+
return False
|
|
133
|
+
except HTTPError as e:
|
|
142
134
|
return False
|
|
143
135
|
|
|
144
136
|
def _post_login_args_validation(self, args: argparse.Namespace, command: str, is_business_plan_user: bool):
|
|
137
|
+
if getattr(args, "application_name"):
|
|
138
|
+
try:
|
|
139
|
+
pynt_client.get_application_by_name(args.application_name)
|
|
140
|
+
except HTTPError as e:
|
|
141
|
+
if e.response.status_code == 404:
|
|
142
|
+
if getattr(args, "yes") or self._is_auto_create_app_confirmed(args.application_name):
|
|
143
|
+
return
|
|
144
|
+
else:
|
|
145
|
+
raise UserAbortedException()
|
|
146
|
+
if getattr(args, "yes") or self._is_missing_app_id_confirmed():
|
|
147
|
+
return
|
|
148
|
+
else:
|
|
149
|
+
raise UserAbortedException()
|
|
150
|
+
|
|
145
151
|
# Confirm not using application-id flag if applicable
|
|
146
152
|
if getattr(args, "application_id") or command in commands_without_app_id:
|
|
147
153
|
return
|
|
@@ -153,18 +159,18 @@ class PyntCommand:
|
|
|
153
159
|
else:
|
|
154
160
|
raise UserAbortedException()
|
|
155
161
|
|
|
156
|
-
def
|
|
162
|
+
def is_confirmed(self, prompt_history_key: str, confirmation_message: str, default_confirmation: str) -> bool:
|
|
157
163
|
"""
|
|
158
|
-
|
|
164
|
+
Ask for the user's confirmation to continue if he/she wasn't asked in the last week.
|
|
159
165
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
Returns:
|
|
167
|
+
bool: True if the user confirms or he/she has confirmed once in the last week. Otherwise, returns False
|
|
168
|
+
"""
|
|
163
169
|
with StateStore() as state_store:
|
|
164
170
|
current_time = datetime.now()
|
|
165
171
|
prompts_history = state_store.get_prompts_history()
|
|
166
172
|
last_confirmed = prompts_history.get(
|
|
167
|
-
|
|
173
|
+
prompt_history_key, {}).get("last_confirmation", "")
|
|
168
174
|
if last_confirmed:
|
|
169
175
|
# Calculate the time delta
|
|
170
176
|
parsed_datetime = datetime.strptime(
|
|
@@ -173,13 +179,21 @@ class PyntCommand:
|
|
|
173
179
|
if difference < timedelta(days=7):
|
|
174
180
|
return True
|
|
175
181
|
|
|
176
|
-
if prompt.confirmation_prompt_with_timeout(
|
|
177
|
-
|
|
178
|
-
"The Application ID can be fetched from https://app.pynt.io/dashboard/applications.\n" +
|
|
179
|
-
"Do you want to continue without associating the scan?", default="yes", timeout=15):
|
|
180
|
-
prompts_history["missing_app_id"] = {"last_confirmation": current_time.strftime("%Y-%m-%d %H:%M:%S")}
|
|
182
|
+
if prompt.confirmation_prompt_with_timeout(confirmation_message, default=default_confirmation, timeout=15):
|
|
183
|
+
prompts_history[prompt_history_key] = {"last_confirmation": current_time.strftime("%Y-%m-%d %H:%M:%S")}
|
|
181
184
|
state_store.put_prompts_history(
|
|
182
185
|
prompts_history)
|
|
183
186
|
return True
|
|
184
187
|
|
|
185
188
|
return False
|
|
189
|
+
|
|
190
|
+
def _is_missing_app_id_confirmed(self) -> bool:
|
|
191
|
+
return self.is_confirmed("missing_app_id", "Application ID is missing. Use the '--application-id' flag to provide it.\n" +
|
|
192
|
+
"Without an Application ID, the scan will not be associated with your application.\n" +
|
|
193
|
+
"The Application ID can be fetched from https://app.pynt.io/dashboard/applications.\n" +
|
|
194
|
+
"Do you want to continue without associating the scan?", "yes")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _is_auto_create_app_confirmed(self, application_name: str) -> bool:
|
|
198
|
+
return self.is_confirmed("", f"Application {application_name} will be created automatically if it does not exist.\n" +
|
|
199
|
+
f"Do you want to continue with the application name {application_name}?", "yes")
|
pyntcli/commands/root.py
CHANGED
|
@@ -68,6 +68,8 @@ class BaseCommand:
|
|
|
68
68
|
parser.add_argument("--transport-config", type=str, default="")
|
|
69
69
|
parser.add_argument("--application-id", type=str,
|
|
70
70
|
default="", required=False)
|
|
71
|
+
parser.add_argument("--application-name", type=str,
|
|
72
|
+
default="", required=False)
|
|
71
73
|
parser.add_argument("--proxy", type=str, default="", required=False)
|
|
72
74
|
parser.add_argument(
|
|
73
75
|
"--yes",
|
|
@@ -5,6 +5,7 @@ import os
|
|
|
5
5
|
import json
|
|
6
6
|
import argparse
|
|
7
7
|
import threading
|
|
8
|
+
from datetime import datetime
|
|
8
9
|
from typing import List
|
|
9
10
|
import base64
|
|
10
11
|
|
|
@@ -150,6 +151,9 @@ def build_docker_args(integration_name: str, args: argparse.Namespace, port_args
|
|
|
150
151
|
if "application_id" in args and args.application_id:
|
|
151
152
|
docker_arguments += ["--application-id", args.application_id]
|
|
152
153
|
|
|
154
|
+
if "application_name" in args and args.application_name:
|
|
155
|
+
docker_arguments += ["--application-name", args.application_name]
|
|
156
|
+
|
|
153
157
|
if "proxy" in args and args.proxy:
|
|
154
158
|
docker_arguments += ["--proxy", args.proxy]
|
|
155
159
|
|
|
@@ -190,6 +194,35 @@ def get_docker_mounts(args: argparse.Namespace) -> list:
|
|
|
190
194
|
return mounts
|
|
191
195
|
|
|
192
196
|
|
|
197
|
+
class DockerLogFollower(threading.Thread):
|
|
198
|
+
def __init__(self, docker_exec: str, container_id: str):
|
|
199
|
+
super().__init__(target=self._run, name="docker logs follower")
|
|
200
|
+
self.docker_exec = docker_exec
|
|
201
|
+
self.container_id = container_id
|
|
202
|
+
|
|
203
|
+
def _run(self):
|
|
204
|
+
logs_process = subprocess.Popen(
|
|
205
|
+
[self.docker_exec, "logs", "-f", self.container_id],
|
|
206
|
+
stdout=subprocess.PIPE,
|
|
207
|
+
stderr=subprocess.STDOUT,
|
|
208
|
+
text=True,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
while True:
|
|
212
|
+
line = logs_process.stdout.readline()
|
|
213
|
+
if not line:
|
|
214
|
+
break
|
|
215
|
+
|
|
216
|
+
now = datetime.now().astimezone().strftime("%Y-%m-%d %H:%M:%S %z")
|
|
217
|
+
log_line = ui_thread.Text(f"{now} [container]", "default on grey53")
|
|
218
|
+
log_line.append(f" {line}", "bold yellow on default")
|
|
219
|
+
|
|
220
|
+
ui_thread.print(log_line)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
logs_process.wait()
|
|
225
|
+
|
|
193
226
|
class PyntContainerNative:
|
|
194
227
|
def __init__(self, container_config: DockerContainerConfig):
|
|
195
228
|
self.config = container_config
|
|
@@ -252,37 +285,20 @@ class PyntContainerNative:
|
|
|
252
285
|
process = subprocess.Popen(docker_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
253
286
|
stdout, stderr = process.communicate()
|
|
254
287
|
|
|
255
|
-
if stderr:
|
|
256
|
-
print(stderr)
|
|
257
|
-
|
|
258
288
|
container_id = stdout.strip()
|
|
259
289
|
|
|
260
290
|
if process.returncode and process.returncode != 0:
|
|
261
|
-
|
|
262
|
-
|
|
291
|
+
formatted_response = f"Unable to perform docker run command, return code: {process.returncode}"
|
|
292
|
+
if ui_thread.VERBOSE:
|
|
293
|
+
if stderr is not None and len(stderr) > 0:
|
|
294
|
+
formatted_response += f"\nstderr\n---\n\n{stderr}"
|
|
295
|
+
if stdout is not None and len(stdout) > 0:
|
|
296
|
+
formatted_response += f"\nstdout\n---\n\n{stdout}"
|
|
297
|
+
raise DockerNativeUnavailableException(formatted_response)
|
|
263
298
|
|
|
264
|
-
# Start log streaming in a separate thread
|
|
265
299
|
if ui_thread.VERBOSE:
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
log_thread.start()
|
|
269
|
-
|
|
270
|
-
def stream_docker_logs(self, container_id):
|
|
271
|
-
logs_process = subprocess.Popen(
|
|
272
|
-
['docker', 'logs', '-f', container_id],
|
|
273
|
-
stdout=subprocess.PIPE,
|
|
274
|
-
stderr=subprocess.PIPE,
|
|
275
|
-
text=True
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
while True:
|
|
279
|
-
log_output = logs_process.stdout.readline()
|
|
280
|
-
if log_output == '' and logs_process.poll() is not None:
|
|
281
|
-
break
|
|
282
|
-
if log_output:
|
|
283
|
-
print(log_output.strip())
|
|
284
|
-
|
|
285
|
-
logs_process.stdout.close()
|
|
300
|
+
# Start log streaming in a separate thread
|
|
301
|
+
DockerLogFollower(docker_exec, container_id).start()
|
|
286
302
|
|
|
287
303
|
def kill_other_instances(self, report_to_user=True):
|
|
288
304
|
ui_thread.print_verbose("Killing other pynt containers if such exist")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .saas_client import *
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
import pyntcli.log.log as log
|
|
5
|
+
from pyntcli.store import CredStore
|
|
6
|
+
|
|
7
|
+
PYNT_SAAS = os.environ.get("PYNT_SAAS_URL", "https://api.pynt.io/v1")
|
|
8
|
+
logger = log.get_logger()
|
|
9
|
+
|
|
10
|
+
class PyntClient:
|
|
11
|
+
def __init__(self, base_url=PYNT_SAAS):
|
|
12
|
+
self.base_url = base_url
|
|
13
|
+
|
|
14
|
+
def _get_headers(self):
|
|
15
|
+
headers = {}
|
|
16
|
+
with CredStore() as store:
|
|
17
|
+
access_token = store.get_access_token()
|
|
18
|
+
token_type = store.get_token_type()
|
|
19
|
+
headers["Authorization"] = f"{token_type} {access_token}"
|
|
20
|
+
return headers
|
|
21
|
+
|
|
22
|
+
def get_config(self):
|
|
23
|
+
url = f"{self.base_url}/config"
|
|
24
|
+
headers = self._get_headers()
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
response = requests.get(url, headers=headers, timeout=10)
|
|
28
|
+
response.raise_for_status()
|
|
29
|
+
return response.json() # returning actual data
|
|
30
|
+
|
|
31
|
+
except requests.exceptions.HTTPError as e:
|
|
32
|
+
logger.error(f"HTTP error accessing '{url}': {e}")
|
|
33
|
+
raise e
|
|
34
|
+
except requests.exceptions.RequestException as e:
|
|
35
|
+
logger.error(f"Error accessing '{url}': {e}")
|
|
36
|
+
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
def get_application_by_name(self, application_name):
|
|
40
|
+
url = f"{self.base_url}/application/{application_name}"
|
|
41
|
+
headers = self._get_headers()
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
response = requests.get(url, headers=headers)
|
|
45
|
+
response.raise_for_status()
|
|
46
|
+
return response.json() # returning actual data
|
|
47
|
+
|
|
48
|
+
except requests.exceptions.HTTPError as e:
|
|
49
|
+
logger.error(f"HTTP error accessing '{url}': {e}")
|
|
50
|
+
raise e
|
|
51
|
+
except requests.exceptions.RequestException as e:
|
|
52
|
+
logger.error(f"Error accessing '{url}': {e}")
|
|
53
|
+
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
pynt_client = PyntClient()
|
pyntcli/ui/pynt_errors.py
CHANGED
|
@@ -2,14 +2,12 @@ from pyntcli.ui import ui_thread
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def unexpected_error(original):
|
|
5
|
-
printer_text = ui_thread.PrinterText("An Unexpected Error Occurred", style=ui_thread.PrinterText.WARNING)
|
|
6
|
-
.with_line("")
|
|
5
|
+
printer_text = ui_thread.PrinterText("An Unexpected Error Occurred: ", style=ui_thread.PrinterText.WARNING)
|
|
7
6
|
|
|
8
7
|
msg = str(original) or repr(original)
|
|
9
|
-
if msg
|
|
10
|
-
printer_text.with_line(f"e: {msg}")
|
|
8
|
+
printer_text.text.append(msg if msg else "Unknown error")
|
|
11
9
|
|
|
12
|
-
printer_text = printer_text.with_line(
|
|
10
|
+
printer_text = printer_text.with_line("").with_line(
|
|
13
11
|
"Please tell us about it in our community channel and we will help you figure it out:",
|
|
14
12
|
style=ui_thread.PrinterText.HEADER) \
|
|
15
13
|
.with_line("https://join.slack.com/t/pynt-community/shared_invite/zt-1mvacojz5-WNjbH4HN8iksmKpCLTxOiQ",
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
ignoreTests/conftest.py,sha256=gToq5K74GtgeGQXjFvXSzMaE6axBYxAzcFG5XJPOXjI,427
|
|
2
2
|
ignoreTests/auth/login.py,sha256=7GeBirHTD9t6EassLYsegCw1FZHkfjvVW1Z5uybHzgM,3801
|
|
3
3
|
ignoreTests/store/cred_store.py,sha256=_7-917EtNC9eKEumO2_lt-7KuDmCwOZFaowCm7DbA_A,254
|
|
4
|
-
pyntcli/__init__.py,sha256=
|
|
4
|
+
pyntcli/__init__.py,sha256=WH7k6Lp9d5LeVrO9NrIvNHTU68a2Yw4l0K-_6mGJeDk,24
|
|
5
5
|
pyntcli/main.py,sha256=RD0W2_0ogYBCXubo-YewxHYkiIXxNv6NkZOh3n1VujE,5964
|
|
6
6
|
pyntcli/analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
pyntcli/analytics/send.py,sha256=0hJ0WJNFHLqyohtRr_xOg5WEXzxHrUOlcePPg-k65Hk,3846
|
|
8
8
|
pyntcli/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
pyntcli/auth/login.py,sha256=Oz1DtEZje0afgJcHSwEFHcH78X-QD5Mjn0CQ9ZgCfQU,5844
|
|
10
10
|
pyntcli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
pyntcli/commands/burp.py,sha256=
|
|
12
|
-
pyntcli/commands/command.py,sha256=
|
|
13
|
-
pyntcli/commands/har.py,sha256=
|
|
11
|
+
pyntcli/commands/burp.py,sha256=9kcqjC9Rgj5oZimGZuA_oO71Hn2Z3py8k5vr-eMKnUM,14317
|
|
12
|
+
pyntcli/commands/command.py,sha256=ulxhWyTnuqQfyNy5somqBbQoTCvd0Hg4OnPJ8thJzAs,11078
|
|
13
|
+
pyntcli/commands/har.py,sha256=laVRjG35LDEykoSfRIuEwHYfLstui6EpPxSjcam64ng,4719
|
|
14
14
|
pyntcli/commands/id_command.py,sha256=UBEgMIpm4vauTCsKyixltiGUolNg_OfHEJvJ_i5BpJY,943
|
|
15
|
-
pyntcli/commands/listen.py,sha256=
|
|
16
|
-
pyntcli/commands/newman.py,sha256=
|
|
15
|
+
pyntcli/commands/listen.py,sha256=RTlUt2oq5_BPeBZpG5yQ6GPAG_Cf0JVrUrkzz8uw9ns,9042
|
|
16
|
+
pyntcli/commands/newman.py,sha256=w0d0Pi1swJQ8E3oRs6vsgw_591sl-4bcLpWZwuBXmDI,5282
|
|
17
17
|
pyntcli/commands/postman.py,sha256=kN1PkzPpcUnsbirg17AN9JwJZu6VBt6OeKYrLGrvtFc,4964
|
|
18
|
-
pyntcli/commands/pynt_cmd.py,sha256=
|
|
19
|
-
pyntcli/commands/root.py,sha256=
|
|
18
|
+
pyntcli/commands/pynt_cmd.py,sha256=TcsKVl0QZLEDIZjo-977IY6k4MAXVk_hljraW1eJmyg,7790
|
|
19
|
+
pyntcli/commands/root.py,sha256=bTGlFroeK7WG9dAhFkVTVnpEM-Gdp8QKCuTxW_QWNlQ,4441
|
|
20
20
|
pyntcli/commands/static_file_extensions.py,sha256=PZJb02BI-64tbU-j3rdCNsXzTh7gkIDGxGKbKNw3h5k,1995
|
|
21
21
|
pyntcli/commands/sub_command.py,sha256=GF3-rE_qk2L4jGPFqHLm9SdGINmu3EakhjJTFyWjRms,374
|
|
22
22
|
pyntcli/commands/template.py,sha256=wl-0GhIUUqdO39fyoO7mMsEKXnYqG32XkQdUJhLkdiA,8047
|
|
@@ -25,7 +25,9 @@ pyntcli/log/__init__.py,sha256=cOGwOYzMoshEbZiiasBGkj6wF0SBu3Jdpl-AuakDesw,19
|
|
|
25
25
|
pyntcli/log/log.py,sha256=YXCvcCzuhQ5QUT2L02uQEdN_lTCzLEuet4OnLuEnjlM,112
|
|
26
26
|
pyntcli/pynt_docker/__init__.py,sha256=PQIOVxc7XXtMLfEX7ojgwf_Z3mmTllO3ZvzUZTPOxQY,30
|
|
27
27
|
pyntcli/pynt_docker/container_utils.py,sha256=_Onn7loInzyJAG2-Uk6CGpsuRyelmUFHOvtJj4Uzi9A,175
|
|
28
|
-
pyntcli/pynt_docker/pynt_container.py,sha256=
|
|
28
|
+
pyntcli/pynt_docker/pynt_container.py,sha256=4vW12inRuKgsUM5K8NHTEjPZE1Qp8F62_J0gy6FjiRU,14506
|
|
29
|
+
pyntcli/saas_client/__init__.py,sha256=HPBzoC5a6F5_WkHubcjq_W4m1OQ9i0TX8QXBtJlKm1M,26
|
|
30
|
+
pyntcli/saas_client/saas_client.py,sha256=7mJNo2x4Oy2N4NKdHyGRxXZUk_VHZvRu1x586rojrp0,1756
|
|
29
31
|
pyntcli/store/__init__.py,sha256=1fP8cEAQCF_myja3gnhHH9FEqtBiOJ-2aBmUXSKBdFA,41
|
|
30
32
|
pyntcli/store/json_connector.py,sha256=UGs3uORw3iyn0YJ8kzab-veEZToA6d-ByXYuqEleWsA,560
|
|
31
33
|
pyntcli/store/store.py,sha256=Kl_HT9FJFdKlAH7SwAt3g4-bW-r-1ve_u13OPggQai0,2529
|
|
@@ -35,13 +37,13 @@ pyntcli/transport/pynt_requests.py,sha256=gOPwBpPj6qIymDRFNgcQmwoI5Rqs4GMk4pfBva
|
|
|
35
37
|
pyntcli/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
38
|
pyntcli/ui/progress.py,sha256=RrnO_jJNunoyupylakmWmHOEPw3lh99OHpKBzL6OBiE,1008
|
|
37
39
|
pyntcli/ui/prompt.py,sha256=tK3BFYvgT7ZgSrsN5ASkltcsbhy8tOdNfEjRyCjOk6Q,1570
|
|
38
|
-
pyntcli/ui/pynt_errors.py,sha256=
|
|
40
|
+
pyntcli/ui/pynt_errors.py,sha256=4CTUnO6D8HD4JFWwKsNqdmhp5XugfFK7wJT5TK3k-Bc,686
|
|
39
41
|
pyntcli/ui/report.py,sha256=W-icPSZrGLOubXgam0LpOvHLl_aZg9Zx9qIkL8Ym5PE,1930
|
|
40
42
|
pyntcli/ui/ui_thread.py,sha256=XUBgLpYQjVhrilU-ofw7VSXgTiwneSdTxm61EvC3x4Q,5091
|
|
41
43
|
tests/test_utils.py,sha256=t5fTQUk1U_Js6iMxcGYGqt4C-crzOJ0CqCKtLkRtUi0,2050
|
|
42
|
-
tests/commands/test_pynt_cmd.py,sha256=
|
|
43
|
-
pyntcli-0.1.
|
|
44
|
-
pyntcli-0.1.
|
|
45
|
-
pyntcli-0.1.
|
|
46
|
-
pyntcli-0.1.
|
|
47
|
-
pyntcli-0.1.
|
|
44
|
+
tests/commands/test_pynt_cmd.py,sha256=J4JrEuD_qSVN76Fu6bKRjrxWSwCTXVEAzVPYdXMa0tI,8826
|
|
45
|
+
pyntcli-0.1.116.dist-info/METADATA,sha256=68McFg0rYxmguHJX3Tc-YVRv9pg-zyyxNuUN1H_283M,427
|
|
46
|
+
pyntcli-0.1.116.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
|
47
|
+
pyntcli-0.1.116.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
|
|
48
|
+
pyntcli-0.1.116.dist-info/top_level.txt,sha256=64XSgBzSpgwjYjEKHZE7q3JH2a816zEeyZBXfJi3AKI,42
|
|
49
|
+
pyntcli-0.1.116.dist-info/RECORD,,
|
tests/commands/test_pynt_cmd.py
CHANGED
|
@@ -8,18 +8,16 @@ import requests
|
|
|
8
8
|
|
|
9
9
|
class TestIsBusinessPlanUser(unittest.TestCase):
|
|
10
10
|
|
|
11
|
-
@patch('
|
|
12
|
-
@patch('pyntcli.
|
|
13
|
-
def test_is_business_plan_user_success(self,
|
|
11
|
+
@patch('requests.get')
|
|
12
|
+
@patch('pyntcli.saas_client.saas_client.CredStore')
|
|
13
|
+
def test_is_business_plan_user_success(self, mock_requests_get, mock_cred_store):
|
|
14
14
|
# Mock the CredStore context manager
|
|
15
|
-
mock_store_instance =
|
|
15
|
+
mock_store_instance = mock_cred_store.return_value.__enter__.return_value
|
|
16
16
|
mock_store_instance.get_access_token.return_value = 'fake_token'
|
|
17
17
|
mock_store_instance.get_token_type.return_value = 'Bearer'
|
|
18
|
-
mock_cred_store.return_value.__enter__.return_value = mock_store_instance
|
|
19
18
|
|
|
20
19
|
# Mock the requests.get response
|
|
21
20
|
mock_response = MagicMock()
|
|
22
|
-
mock_response.status_code = 200
|
|
23
21
|
mock_requests_get.return_value = mock_response
|
|
24
22
|
|
|
25
23
|
# Instantiate the class and call the method
|
|
@@ -29,18 +27,18 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
29
27
|
# Assert the result
|
|
30
28
|
self.assertTrue(result)
|
|
31
29
|
|
|
32
|
-
@patch('
|
|
33
|
-
@patch('pyntcli.
|
|
34
|
-
def test_is_business_plan_user_failure(self,
|
|
30
|
+
@patch('requests.get')
|
|
31
|
+
@patch('pyntcli.saas_client.saas_client.CredStore')
|
|
32
|
+
def test_is_business_plan_user_failure(self,mock_cred_store, mock_requests_get):
|
|
35
33
|
# Mock the CredStore context manager
|
|
36
|
-
mock_store_instance =
|
|
34
|
+
mock_store_instance = mock_cred_store.return_value.__enter__.return_value
|
|
37
35
|
mock_store_instance.get_access_token.return_value = 'fake_token'
|
|
38
36
|
mock_store_instance.get_token_type.return_value = 'Bearer'
|
|
39
|
-
|
|
37
|
+
|
|
40
38
|
|
|
41
39
|
# Mock the requests.get response
|
|
42
40
|
mock_response = MagicMock()
|
|
43
|
-
mock_response.
|
|
41
|
+
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError(response=MagicMock(status_code=403))
|
|
44
42
|
mock_requests_get.return_value = mock_response
|
|
45
43
|
|
|
46
44
|
# Instantiate the class and call the method
|
|
@@ -50,14 +48,13 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
50
48
|
# Assert the result
|
|
51
49
|
self.assertFalse(result)
|
|
52
50
|
|
|
53
|
-
@patch('
|
|
54
|
-
@patch('pyntcli.
|
|
51
|
+
@patch('requests.get')
|
|
52
|
+
@patch('pyntcli.saas_client.saas_client.CredStore')
|
|
55
53
|
def test_is_business_plan_user_exception(self, mock_cred_store, mock_requests_get):
|
|
56
54
|
# Mock the CredStore context manager
|
|
57
|
-
mock_store_instance =
|
|
55
|
+
mock_store_instance = mock_cred_store.return_value.__enter__.return_value
|
|
58
56
|
mock_store_instance.get_access_token.return_value = 'fake_token'
|
|
59
57
|
mock_store_instance.get_token_type.return_value = 'Bearer'
|
|
60
|
-
mock_cred_store.return_value.__enter__.return_value = mock_store_instance
|
|
61
58
|
|
|
62
59
|
# Mock the requests.get to raise an exception
|
|
63
60
|
mock_requests_get.side_effect = requests.exceptions.RequestException
|
|
@@ -75,7 +72,7 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
75
72
|
instance = PyntCommand()
|
|
76
73
|
try:
|
|
77
74
|
result = instance._post_login_args_validation(argparse.Namespace(
|
|
78
|
-
application_id="", yes=False), "non-postman-command", True)
|
|
75
|
+
application_id="", application_name="", yes=False), "non-postman-command", True)
|
|
79
76
|
except Exception as e:
|
|
80
77
|
self.fail(f"Unexpected exception raised {e}")
|
|
81
78
|
|
|
@@ -85,7 +82,7 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
85
82
|
instance = PyntCommand()
|
|
86
83
|
try:
|
|
87
84
|
result = instance._post_login_args_validation(argparse.Namespace(
|
|
88
|
-
application_id="", yes=True), "non-postman-command", True)
|
|
85
|
+
application_id="", application_name="", yes=True), "non-postman-command", True)
|
|
89
86
|
except Exception as e:
|
|
90
87
|
self.fail(f"Unexpected exception raised {e}")
|
|
91
88
|
|
|
@@ -95,7 +92,7 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
95
92
|
instance = PyntCommand()
|
|
96
93
|
with self.assertRaises(UserAbortedException):
|
|
97
94
|
result = instance._post_login_args_validation(argparse.Namespace(
|
|
98
|
-
application_id="", yes=False), "non-postman-command", True)
|
|
95
|
+
application_id="", application_name="", yes=False), "non-postman-command", True)
|
|
99
96
|
|
|
100
97
|
@patch.object(PyntCommand, '_is_missing_app_id_confirmed', return_value=False)
|
|
101
98
|
def test_post_login_args_validation_missing_app_id_free_tier(self, _):
|
|
@@ -103,7 +100,7 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
103
100
|
instance = PyntCommand()
|
|
104
101
|
try:
|
|
105
102
|
result = instance._post_login_args_validation(argparse.Namespace(
|
|
106
|
-
application_id="", yes=False), "non-postman-command", False)
|
|
103
|
+
application_id="", application_name="", yes=False), "non-postman-command", False)
|
|
107
104
|
except Exception as e:
|
|
108
105
|
self.fail(f"Unexpected exception raised {e}")
|
|
109
106
|
|
|
@@ -113,9 +110,9 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
113
110
|
instance = PyntCommand()
|
|
114
111
|
try:
|
|
115
112
|
result = instance._post_login_args_validation(
|
|
116
|
-
argparse.Namespace(application_id="", yes=False), "postman", True)
|
|
113
|
+
argparse.Namespace(application_id="", application_name="", yes=False), "postman", True)
|
|
117
114
|
result = instance._post_login_args_validation(
|
|
118
|
-
argparse.Namespace(application_id="", yes=False), "pynt-id", True)
|
|
115
|
+
argparse.Namespace(application_id="", application_name="", yes=False), "pynt-id", True)
|
|
119
116
|
except Exception as e:
|
|
120
117
|
self.fail(f"Unexpected exception raised {e}")
|
|
121
118
|
|
|
@@ -137,6 +134,18 @@ class TestIsBusinessPlanUser(unittest.TestCase):
|
|
|
137
134
|
# Assert the result
|
|
138
135
|
self.assertTrue(result)
|
|
139
136
|
|
|
137
|
+
@patch('pyntcli.commands.pynt_cmd.prompt.confirmation_prompt_with_timeout', return_value=True)
|
|
138
|
+
@patch('requests.get')
|
|
139
|
+
def test_is_auto_create_app_confirmed_auto_confirms(self, mock_requests_get, _):
|
|
140
|
+
mock_response = MagicMock()
|
|
141
|
+
mock_requests_get.return_value = mock_response
|
|
142
|
+
|
|
143
|
+
instance = PyntCommand()
|
|
144
|
+
result = instance._is_auto_create_app_confirmed("app_name")
|
|
145
|
+
|
|
146
|
+
# Assert the result
|
|
147
|
+
self.assertTrue(result)
|
|
148
|
+
|
|
140
149
|
@patch('pyntcli.commands.pynt_cmd.prompt.confirmation_prompt_with_timeout', return_value=False)
|
|
141
150
|
@patch('pyntcli.commands.pynt_cmd.StateStore')
|
|
142
151
|
def test_missing_app_id_confirmation_confirmation_expired_user_aborts(self, mock_state_store, _):
|
|
File without changes
|
|
File without changes
|