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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.114"
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")
@@ -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
  )
@@ -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) ")
@@ -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")
@@ -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 CredStore, StateStore
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 response.status_code == requests.codes.ok:
129
+ if pynt_client.get_config():
136
130
  return True
137
- else:
138
- return False
139
- except requests.exceptions.RequestException as e:
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 _is_missing_app_id_confirmed(self) -> bool:
162
+ def is_confirmed(self, prompt_history_key: str, confirmation_message: str, default_confirmation: str) -> bool:
157
163
  """
158
- Ask for the user's confirmation to continue if he/she wasn't asked in the last week.
164
+ Ask for the user's confirmation to continue if he/she wasn't asked in the last week.
159
165
 
160
- Returns:
161
- bool: True if the user confirms or he/she has confirmed once in the last week. Otherwise, returns False
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
- "missing_app_id", {}).get("last_confirmation", "")
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("Application ID is missing. Use the '--application-id' flag to provide it.\n" +
177
- "Without an Application ID, the scan will not be associated with your application.\n" +
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
- ui_thread.print_verbose(f"Unable to perform docker run command, return code: {process.returncode}")
262
- raise DockerNativeUnavailableException(f"Unable to perform docker run command, return code: {process.returncode}")
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
- log_thread = threading.Thread(target=self.stream_docker_logs, args=(container_id,))
267
- log_thread.daemon = True
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,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pyntcli
3
- Version: 0.1.114
3
+ Version: 0.1.116
4
4
  Summary: Command line utility to handle all of Pynt's different integrations
5
5
  Author-email: Pynt-io <support@pynt.io>
6
6
  Project-URL: Homepage, https://pynt.io
@@ -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=iSRFeK7cDc1GPwfyu8HXg0EPmcdBiD7ztZImO4LqE1E,24
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=AUJU2cIJ-PSUATxYoHRwDy0K5feqCs-mGdkGle2WcDw,14173
12
- pyntcli/commands/command.py,sha256=BLV1XVZfYFYnOq-A3M3CY1rLYB389QLUYzV2ZrKybxU,10921
13
- pyntcli/commands/har.py,sha256=ZPPQFSyP9W1mSo7ankPnWwLzweDwoT4_iMZ7bPwzvoA,4575
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=18D9OdW1EakkK1u54hiOjwAuT5J6nsYb2vqlP1nw8p4,8898
16
- pyntcli/commands/newman.py,sha256=ssMXY7VvYdMCXS38uLftF7uQ4HmDMYYHra4GvZhcR-g,5116
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=AeXxKy8dtZTdwWhTirHVvkPkeFUSoZNb3FRyuwkL6kg,7103
19
- pyntcli/commands/root.py,sha256=Lr31nsx2sgM-o3OYEbfqakaxzXHY6irr9uj-X6QWiqk,4325
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=u87rBT52rxDYNg8gc0NAs3GhTDS1MFwKLpShJkPlKbA,13861
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=00UprD4tFViREv7kuXGQ99PAKGTpXYixxi3Ndeoeiew,689
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=BjGFCFACcSziLrNA6_27t6TjSmvdu54wx9njwLpRSJY,8379
43
- pyntcli-0.1.114.dist-info/METADATA,sha256=qtGIqKnV4wKYJKJNcr9eevjoYBbFUmMKRg79fNoZ82Q,427
44
- pyntcli-0.1.114.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
45
- pyntcli-0.1.114.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
46
- pyntcli-0.1.114.dist-info/top_level.txt,sha256=64XSgBzSpgwjYjEKHZE7q3JH2a816zEeyZBXfJi3AKI,42
47
- pyntcli-0.1.114.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -8,18 +8,16 @@ import requests
8
8
 
9
9
  class TestIsBusinessPlanUser(unittest.TestCase):
10
10
 
11
- @patch('pyntcli.commands.pynt_cmd.requests.get')
12
- @patch('pyntcli.commands.pynt_cmd.CredStore')
13
- def test_is_business_plan_user_success(self, mock_cred_store, mock_requests_get):
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 = MagicMock()
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('pyntcli.commands.pynt_cmd.requests.get')
33
- @patch('pyntcli.commands.pynt_cmd.CredStore')
34
- def test_is_business_plan_user_failure(self, mock_cred_store, mock_requests_get):
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 = MagicMock()
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
- mock_cred_store.return_value.__enter__.return_value = mock_store_instance
37
+
40
38
 
41
39
  # Mock the requests.get response
42
40
  mock_response = MagicMock()
43
- mock_response.status_code = 403
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('pyntcli.commands.pynt_cmd.requests.get')
54
- @patch('pyntcli.commands.pynt_cmd.CredStore')
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 = MagicMock()
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, _):