pyntcli 0.1.29__py3-none-any.whl → 0.1.31__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.
Files changed (66) hide show
  1. build/lib/build/lib/build/lib/pyntcli/__init__.py +1 -0
  2. build/lib/build/lib/build/lib/pyntcli/analytics/__init__.py +0 -0
  3. build/lib/build/lib/build/lib/pyntcli/analytics/send.py +70 -0
  4. build/lib/build/lib/build/lib/pyntcli/auth/__init__.py +0 -0
  5. build/lib/build/lib/build/lib/pyntcli/auth/login.py +156 -0
  6. build/lib/build/lib/build/lib/pyntcli/commands/__init__.py +0 -0
  7. build/lib/build/lib/build/lib/pyntcli/commands/har.py +68 -0
  8. build/lib/build/lib/build/lib/pyntcli/commands/id_command.py +28 -0
  9. build/lib/build/lib/build/lib/pyntcli/commands/newman.py +85 -0
  10. build/lib/build/lib/build/lib/pyntcli/commands/postman.py +58 -0
  11. build/lib/build/lib/build/lib/pyntcli/commands/proxy.py +145 -0
  12. build/lib/build/lib/build/lib/pyntcli/commands/pynt_cmd.py +47 -0
  13. build/lib/build/lib/build/lib/pyntcli/commands/root.py +57 -0
  14. build/lib/build/lib/build/lib/pyntcli/commands/sub_command.py +15 -0
  15. build/lib/build/lib/build/lib/pyntcli/commands/util.py +26 -0
  16. build/lib/build/lib/build/lib/pyntcli/main.py +77 -0
  17. build/lib/build/lib/build/lib/pyntcli/pynt_docker/__init__.py +1 -0
  18. build/lib/build/lib/build/lib/pyntcli/pynt_docker/pynt_container.py +178 -0
  19. build/lib/build/lib/build/lib/pyntcli/store/__init__.py +1 -0
  20. build/lib/build/lib/build/lib/pyntcli/store/json_connector.py +23 -0
  21. build/lib/build/lib/build/lib/pyntcli/store/store.py +55 -0
  22. build/lib/build/lib/build/lib/pyntcli/store/store_connector.py +17 -0
  23. build/lib/build/lib/build/lib/pyntcli/ui/__init__.py +0 -0
  24. build/lib/build/lib/build/lib/pyntcli/ui/progress.py +31 -0
  25. build/lib/build/lib/build/lib/pyntcli/ui/ui_thread.py +168 -0
  26. build/lib/build/lib/build/lib/tests/auth/test_login.py +96 -0
  27. build/lib/build/lib/build/lib/tests/conftest.py +24 -0
  28. build/lib/build/lib/build/lib/tests/store/test_cred_store.py +11 -0
  29. build/lib/build/lib/pyntcli/__init__.py +1 -0
  30. build/lib/build/lib/pyntcli/analytics/__init__.py +0 -0
  31. build/lib/build/lib/pyntcli/analytics/send.py +70 -0
  32. build/lib/build/lib/pyntcli/auth/__init__.py +0 -0
  33. build/lib/build/lib/pyntcli/auth/login.py +156 -0
  34. build/lib/build/lib/pyntcli/commands/__init__.py +0 -0
  35. build/lib/build/lib/pyntcli/commands/har.py +68 -0
  36. build/lib/build/lib/pyntcli/commands/id_command.py +28 -0
  37. build/lib/build/lib/pyntcli/commands/newman.py +85 -0
  38. build/lib/build/lib/pyntcli/commands/postman.py +58 -0
  39. build/lib/build/lib/pyntcli/commands/proxy.py +147 -0
  40. build/lib/build/lib/pyntcli/commands/pynt_cmd.py +47 -0
  41. build/lib/build/lib/pyntcli/commands/root.py +57 -0
  42. build/lib/build/lib/pyntcli/commands/sub_command.py +15 -0
  43. build/lib/build/lib/pyntcli/commands/util.py +26 -0
  44. build/lib/build/lib/pyntcli/main.py +77 -0
  45. build/lib/build/lib/pyntcli/pynt_docker/__init__.py +1 -0
  46. build/lib/build/lib/pyntcli/pynt_docker/pynt_container.py +178 -0
  47. build/lib/build/lib/pyntcli/store/__init__.py +1 -0
  48. build/lib/build/lib/pyntcli/store/json_connector.py +23 -0
  49. build/lib/build/lib/pyntcli/store/store.py +55 -0
  50. build/lib/build/lib/pyntcli/store/store_connector.py +17 -0
  51. build/lib/build/lib/pyntcli/ui/__init__.py +0 -0
  52. build/lib/build/lib/pyntcli/ui/progress.py +31 -0
  53. build/lib/build/lib/pyntcli/ui/ui_thread.py +168 -0
  54. build/lib/build/lib/tests/auth/test_login.py +96 -0
  55. build/lib/build/lib/tests/conftest.py +24 -0
  56. build/lib/build/lib/tests/store/test_cred_store.py +11 -0
  57. build/lib/pyntcli/__init__.py +1 -1
  58. build/lib/pyntcli/commands/proxy.py +1 -0
  59. pyntcli/__init__.py +1 -1
  60. pyntcli/commands/proxy.py +0 -2
  61. {pyntcli-0.1.29.dist-info → pyntcli-0.1.31.dist-info}/METADATA +1 -1
  62. pyntcli-0.1.31.dist-info/RECORD +117 -0
  63. pyntcli-0.1.29.dist-info/RECORD +0 -61
  64. {pyntcli-0.1.29.dist-info → pyntcli-0.1.31.dist-info}/WHEEL +0 -0
  65. {pyntcli-0.1.29.dist-info → pyntcli-0.1.31.dist-info}/entry_points.txt +0 -0
  66. {pyntcli-0.1.29.dist-info → pyntcli-0.1.31.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,96 @@
1
+ from urllib.parse import urlparse
2
+ import json
3
+ from _pytest.monkeypatch import monkeypatch
4
+ import pytest
5
+ import requests
6
+ import requests_mock
7
+ import datetime
8
+ import jwt
9
+ import os
10
+ from cryptography.hazmat.primitives.asymmetric import rsa
11
+ from cryptography.hazmat.primitives import serialization
12
+
13
+ from pyntcli.auth.login import Login, Timeout, InvalidTokenInEnvVarsException, is_jwt_expired, should_login, PYNT_CREDENTIALS
14
+ from pyntcli.store import CredStore
15
+
16
+
17
+ class TestLogin():
18
+ @pytest.fixture
19
+ def mock_webbrowser(self, mocker):
20
+ try:
21
+ mocker.patch("webbrowser.open", return_value=None)
22
+ yield
23
+ finally:
24
+ pass
25
+
26
+ def get_request_url_parameters(self, req: requests.PreparedRequest) :
27
+ u = req.url
28
+ parsed_url = urlparse(u)
29
+ return parsed_url.query
30
+
31
+ def poll_matcher(self, request: requests.PreparedRequest):
32
+ assert "request_id" in self.get_request_url_parameters(request)
33
+
34
+ resp = requests.Response()
35
+ self.login_request_cnt += 1
36
+ if self.login_request_cnt < 2:
37
+ resp.status_code = 404
38
+ return resp
39
+
40
+ resp.status_code = 200
41
+ resp._content = json.dumps({"token": "testToken"}).encode()
42
+ return resp
43
+
44
+ def test_login(self, mock_webbrowser, mock_sleep, mock_expanduser):
45
+ l = Login()
46
+ self.login_request_cnt = 0
47
+ with requests_mock.mock() as m:
48
+ m.add_matcher(self.poll_matcher)
49
+ l.login()
50
+
51
+ assert self.login_request_cnt == 2
52
+ c = CredStore()
53
+ assert c.get("token") == {"token": "testToken"}
54
+
55
+ def test_login_timeout(self, mock_webbrowser, mock_sleep, mock_expanduser):
56
+ l = Login()
57
+ l.login_wait_period = 0
58
+ self.login_request_cnt = 0
59
+ with pytest.raises(Timeout):
60
+ with requests_mock.mock() as m:
61
+ m.add_matcher(self.poll_matcher)
62
+ l.get_token_using_request_id("some_id")
63
+
64
+
65
+ def test_is_jwt_expired(self):
66
+
67
+ private_key = rsa.generate_private_key(
68
+ public_exponent=65537,
69
+ key_size=2048
70
+ ).private_bytes(encoding=serialization.Encoding.PEM,
71
+ format=serialization.PrivateFormat.PKCS8,
72
+ encryption_algorithm=serialization.NoEncryption())
73
+
74
+
75
+ token_data = {
76
+ "exp": int((datetime.datetime.now() - datetime.timedelta(days=1)).timestamp())
77
+ }
78
+
79
+ token = jwt.encode(token_data, private_key.decode(), algorithm="RS256").decode("utf-8")
80
+ assert is_jwt_expired(token) == True
81
+
82
+ token_data = {
83
+ "exp": int((datetime.datetime.now() + datetime.timedelta(days=1)).timestamp())
84
+ }
85
+
86
+ token = jwt.encode(token_data, private_key.decode(), algorithm="RS256").decode("utf-8")
87
+ assert is_jwt_expired(token) == False
88
+
89
+ def test_login_using_env_vars(self, mocker, mock_expanduser):
90
+ creds = json.dumps({"token": {"refresh_token": "some data"}})
91
+ mocker.patch.dict(os.environ, {PYNT_CREDENTIALS: creds})
92
+ assert should_login() == False
93
+
94
+ os.environ[PYNT_CREDENTIALS] = "some bad credentials"
95
+ with pytest.raises(InvalidTokenInEnvVarsException):
96
+ should_login()
@@ -0,0 +1,24 @@
1
+ import tempfile
2
+ import pytest
3
+ import shutil
4
+
5
+ import sys
6
+ sys.path.append("../")
7
+
8
+ @pytest.fixture
9
+ def mock_expanduser( mocker):
10
+ dir = tempfile.mkdtemp()
11
+ try:
12
+ mocker.patch("os.path.expanduser", return_value=dir)
13
+ yield
14
+ finally:
15
+ shutil.rmtree(dir)
16
+
17
+ @pytest.fixture
18
+ def mock_sleep( mocker):
19
+ try:
20
+ mocker.patch("time.sleep", return_value=None)
21
+ yield
22
+ finally:
23
+ pass
24
+
@@ -0,0 +1,11 @@
1
+ import tempfile
2
+ import shutil
3
+ import pytest
4
+
5
+ from pyntcli.store import CredStore
6
+
7
+ class TestCredStore():
8
+ def test_get_credentials(self, mock_expanduser):
9
+ c = CredStore()
10
+ c.put("data", "value")
11
+ assert c.get("data") == "value"
@@ -0,0 +1 @@
1
+ __version__ = "0.1.31"
File without changes
@@ -0,0 +1,70 @@
1
+ import requests
2
+ import time
3
+ import platform
4
+
5
+ from pyntcli import __version__
6
+
7
+ PYNT_DEFAULT_USER_ID = "d9e3b82b-2900-43bf-8c8f-7ffe2f0cda36"
8
+ MIXPANEL_TOKEN = "05c26edb86084bbbb803eed6818cd8aa"
9
+ MIXPANEL_URL = "https://api-eu.mixpanel.com/track?ip=1"
10
+
11
+ def stop():
12
+ if not AnalyticsSender._instance:
13
+ return
14
+ AnalyticsSender.instance().done()
15
+
16
+ def emit(event, properties=None):
17
+ AnalyticsSender.instance().emit(event, properties)
18
+
19
+ def set_user_id(user_id):
20
+ AnalyticsSender.instance().set_user_id(user_id)
21
+
22
+ CLI_START = "cli_start"
23
+ LOGIN_START = "cli_login_start"
24
+ LOGIN_DONE = "cli_login_done"
25
+ ERROR = "error"
26
+
27
+ class AnalyticsSender():
28
+ _instance = None
29
+
30
+ def __init__(self, user_id=PYNT_DEFAULT_USER_ID) -> None:
31
+ self.user_id = user_id
32
+ self.version = __version__
33
+ self.events = []
34
+
35
+ @staticmethod
36
+ def instance():
37
+ if not AnalyticsSender._instance:
38
+ AnalyticsSender._instance = AnalyticsSender()
39
+
40
+ return AnalyticsSender._instance
41
+
42
+ def base_event(self, event_type):
43
+ return {
44
+ "event": event_type,
45
+ "properties": {
46
+ "time": time.time(),
47
+ "distinct_id": self.user_id,
48
+ "$os": platform.platform(),
49
+ "cli_version": self.version,
50
+ "token": MIXPANEL_TOKEN
51
+ }
52
+ }
53
+
54
+ def emit(self, event, properties):
55
+ base_event = self.base_event(event)
56
+
57
+ if properties:
58
+ for k,v in properties.items():
59
+ base_event["properties"][k] = v
60
+
61
+ self.events.append(base_event)
62
+
63
+ def set_user_id(self, user_id):
64
+ self.user_id = user_id
65
+ for i, _ in enumerate(self.events):
66
+ self.events[i]["properties"]["distinct_id"] = user_id
67
+
68
+ def done(self):
69
+ requests.post(MIXPANEL_URL, json=self.events)
70
+ self.events = []
File without changes
@@ -0,0 +1,156 @@
1
+ from base64 import b64decode
2
+ import requests
3
+ import webbrowser
4
+ import uuid
5
+ import urllib.parse
6
+ import datetime
7
+ import time
8
+ import json
9
+ import os
10
+
11
+ from pyntcli.ui import ui_thread
12
+ from pyntcli.store import CredStore
13
+
14
+ class LoginException(Exception):
15
+ pass
16
+
17
+ class Timeout(LoginException):
18
+ pass
19
+
20
+ class InvalidTokenInEnvVarsException(LoginException):
21
+ pass
22
+
23
+ PYNT_CREDENTIALS = "PYNT_CREDENTIALS"
24
+
25
+ class Login():
26
+ def __init__(self) -> None:
27
+ self.delay = 5
28
+ self.base_authorization_url = "https://pynt.io/login?"
29
+ self.poll_url = "https://n592meacjj.execute-api.us-east-1.amazonaws.com/default/cli_validate_login"
30
+ self.login_wait_period = (60 *3) #3 minutes
31
+
32
+ def create_login_request(self):
33
+ request_id = uuid.uuid4()
34
+ request_url = self.base_authorization_url + urllib.parse.urlencode({"request_id": request_id, "utm_source": "cli"})
35
+ webbrowser.open(request_url)
36
+
37
+ ui_thread.print(ui_thread.PrinterText("To continue, you need to log in to your account.")\
38
+ .with_line("You will now be redirected to the login page.") \
39
+ .with_line("") \
40
+ .with_line("If you are not automatically redirected, please click on the link provided below (or copy to your web browser)") \
41
+ .with_line(request_url))
42
+ return request_id
43
+
44
+ def get_token_using_request_id(self, request_id):
45
+ with ui_thread.spinner("Waiting...", "point"):
46
+ start = time.time()
47
+ while start + self.login_wait_period > time.time():
48
+ response = requests.get(self.poll_url, params={"request_id": request_id})
49
+ if response.status_code == 200:
50
+ return response.json()
51
+ time.sleep(self.delay)
52
+ raise Timeout()
53
+
54
+ def login(self):
55
+ id = self.create_login_request()
56
+ token = self.get_token_using_request_id(id)
57
+ with CredStore() as store:
58
+ store.put("token", token)
59
+
60
+
61
+ def refresh_request(refresh_token):
62
+ return requests.post("https://auth.pynt.io/default/refresh", json={"refresh_token": refresh_token})
63
+
64
+ def refresh_token():
65
+ token = None
66
+ with CredStore() as store:
67
+ token = store.get("token")
68
+
69
+ if not token:
70
+ Login().login()
71
+
72
+ access_token = token.get("access_token")
73
+ if access_token and not is_jwt_expired(access_token):
74
+ return
75
+
76
+ refresh = token.get("refresh_token", None)
77
+ if not refresh:
78
+ Login().login()
79
+ return
80
+
81
+ refresh_response = refresh_request(refresh)
82
+ if refresh_response.status_code != 200:
83
+ Login().login()
84
+ return
85
+
86
+ with CredStore() as store:
87
+ token["access_token"] = refresh_response.json()["token"]
88
+ store.put("token", token)
89
+
90
+ def decode_jwt(jwt_token):
91
+ splited = jwt_token.split(".")
92
+ if len(splited) != 3:
93
+ return None
94
+
95
+ return json.loads(b64decode(splited[1] + '=' * (-len(splited[1]) % 4)))
96
+
97
+ def user_id():
98
+ with CredStore() as store:
99
+ token = store.get("token")
100
+ if not token:
101
+ return None
102
+
103
+ decoded = decode_jwt(token["access_token"])
104
+ if not decoded:
105
+ return None
106
+
107
+ return decoded.get("sub", None)
108
+
109
+ return None
110
+
111
+ def is_jwt_expired(jwt_token):
112
+ decoded = decode_jwt(jwt_token)
113
+ if not decoded:
114
+ return True
115
+
116
+ exp = decoded.get("exp", None)
117
+ if not exp:
118
+ return True
119
+
120
+ return datetime.datetime.fromtimestamp(exp) < datetime.datetime.now() + datetime.timedelta(minutes=1)
121
+
122
+ def validate_creds_structure(data):
123
+ try:
124
+ creds = json.loads(data.replace("\n", ""))
125
+ token = creds.get("token", None)
126
+ if not token:
127
+ raise InvalidTokenInEnvVarsException()
128
+ if not isinstance(token, dict):
129
+ raise InvalidTokenInEnvVarsException()
130
+
131
+ refresh_token = token.get("refresh_token", None)
132
+ if not refresh_token:
133
+ raise InvalidTokenInEnvVarsException()
134
+
135
+ return token
136
+ except json.JSONDecodeError:
137
+ raise InvalidTokenInEnvVarsException()
138
+
139
+
140
+ def should_login():
141
+ env_creds = os.environ.get(PYNT_CREDENTIALS, None)
142
+ if env_creds:
143
+ validated_creds = validate_creds_structure(env_creds)
144
+ with CredStore() as store:
145
+ store.put("token", validated_creds)
146
+
147
+ with CredStore() as store:
148
+ token = store.get("token")
149
+
150
+ if not token or token == store.connector.default_value:
151
+ return True
152
+
153
+ if not token.get("refresh_token"):
154
+ return True
155
+
156
+ return False
File without changes
@@ -0,0 +1,68 @@
1
+ import argparse
2
+ import time
3
+ import os
4
+
5
+ from pyntcli.store.store import CredStore
6
+ from pyntcli.pynt_docker import pynt_container
7
+ from pyntcli.ui import ui_thread
8
+ from pyntcli.ui.progress import connect_progress_ws, wrap_ws_progress
9
+ from pyntcli.commands import sub_command, util
10
+
11
+ def har_usage():
12
+ return ui_thread.PrinterText("Integration with static har file testing") \
13
+ .with_line("") \
14
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER) \
15
+ .with_line("\tpynt har [OPTIONS]") \
16
+ .with_line("") \
17
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER) \
18
+ .with_line("\t--har - Path to har file")
19
+
20
+ class HarSubCommand(sub_command.PyntSubCommand):
21
+ def __init__(self, name) -> None:
22
+ super().__init__(name)
23
+
24
+ def usage(self, *args):
25
+ ui_thread.print(har_usage())
26
+
27
+ def add_cmd(self, parent: argparse._SubParsersAction) -> argparse.ArgumentParser:
28
+ har_cmd = parent.add_parser(self.name)
29
+ har_cmd.add_argument("--har", type=str, required=True)
30
+ har_cmd.print_usage = self.usage
31
+ har_cmd.print_help = self.usage
32
+ return har_cmd
33
+
34
+ def run_cmd(self, args: argparse.Namespace):
35
+ port = str(util.find_open_port())
36
+ docker_type , docker_arguments = pynt_container.get_container_with_arguments(pynt_container.PyntDockerPort(src=port, dest=port, name="--port"))
37
+ mounts = []
38
+
39
+ if not os.path.isfile(args.har):
40
+ ui_thread.print(ui_thread.PrinterText("Could not find the provided har path, please provide with a valid har path", ui_thread.PrinterText.WARNING))
41
+ return
42
+
43
+ har_name = os.path.basename(args.har)
44
+ docker_arguments += ["--har", har_name]
45
+ mounts.append(pynt_container.create_mount(os.path.abspath(args.har), "/etc/pynt/{}".format(har_name)))
46
+
47
+ mounts.append(pynt_container.create_mount(CredStore().get_path(), "/app/creds.json"))
48
+
49
+ if "insecure" in args and args.insecure:
50
+ docker_arguments.append("--insecure")
51
+
52
+ if "dev_flags" in args:
53
+ docker_arguments += args.dev_flags.split(" ")
54
+
55
+ har_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
56
+ tag="har-latest",
57
+ detach=True,
58
+ mounts=mounts,
59
+ args=docker_arguments)
60
+
61
+ har_docker.run(docker_type)
62
+
63
+ util.wait_for_healthcheck("http://localhost:{}".format(port))
64
+ ui_thread.print_generator(ui_thread.AnsiText.wrap_gen(har_docker.stdout))
65
+
66
+ with ui_thread.progress(wrap_ws_progress(connect_progress_ws("ws://localhost:{}/progress".format(port))), "scan in progress..."):
67
+ while har_docker.is_alive():
68
+ time.sleep(1)
@@ -0,0 +1,28 @@
1
+ import argparse
2
+
3
+ from pyntcli.store.store import CredStore
4
+ from pyntcli.commands import sub_command
5
+ from pyntcli.ui import ui_thread
6
+
7
+ def pyntid_usage():
8
+ return ui_thread.PrinterText("View your pynt-id to use when running pynt in CI pipeline") \
9
+ .with_line("") \
10
+ .with_line("Usage:",style=ui_thread.PrinterText.HEADER) \
11
+ .with_line("\tpynt pynt-id")
12
+
13
+ class PyntShowIdCommand(sub_command.PyntSubCommand):
14
+ def __init__(self, name) -> None:
15
+ super().__init__(name)
16
+
17
+ def usage(self, *args):
18
+ ui_thread.print(pyntid_usage())
19
+
20
+ def add_cmd(self, parent: argparse._SubParsersAction) -> argparse.ArgumentParser:
21
+ cmd = parent.add_parser(self.name)
22
+ cmd.print_usage = self.usage
23
+ cmd.print_help = self.usage
24
+ return cmd
25
+
26
+ def run_cmd(self, args: argparse.Namespace):
27
+ creds_path = CredStore().get_path()
28
+ ui_thread.print(open(creds_path, "r").read())
@@ -0,0 +1,85 @@
1
+ import argparse
2
+ import time
3
+ import os
4
+
5
+ from pyntcli.store.store import CredStore
6
+ from pyntcli.pynt_docker import pynt_container
7
+ from pyntcli.commands import sub_command, util
8
+ from pyntcli.ui import ui_thread
9
+ from pyntcli.ui.progress import connect_progress_ws, wrap_ws_progress
10
+
11
+ def newman_usage():
12
+ return ui_thread.PrinterText("Integration with newman, run scan using postman collection from the CLI") \
13
+ .with_line("") \
14
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER) \
15
+ .with_line("\tpynt newman [OPTIONS]") \
16
+ .with_line("") \
17
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER) \
18
+ .with_line("\t--collection - Postman collection file name") \
19
+ .with_line("\t--environment - Postman environment file name") \
20
+ .with_line("\t--reporters output results to json")
21
+
22
+ class NewmanSubCommand(sub_command.PyntSubCommand):
23
+ def __init__(self, name) -> None:
24
+ super().__init__(name)
25
+
26
+ def usage(self, *args):
27
+ ui_thread.print(newman_usage())
28
+
29
+ def add_cmd(self, parent: argparse._SubParsersAction) -> argparse.ArgumentParser:
30
+ newman_cmd = parent.add_parser(self.name)
31
+ newman_cmd.add_argument("--collection", type=str, required=True)
32
+ newman_cmd.add_argument("--environment", type=str, required=False)
33
+ newman_cmd.add_argument("--reporters", type=bool, required=False)
34
+ newman_cmd.print_usage = self.usage
35
+ newman_cmd.print_help = self.usage
36
+ return newman_cmd
37
+
38
+ def run_cmd(self, args: argparse.Namespace):
39
+ port = str(util.find_open_port())
40
+ docker_type , docker_arguments = pynt_container.get_container_with_arguments(pynt_container.PyntDockerPort(src=port, dest=port, name="--port"))
41
+ mounts = []
42
+
43
+ if not os.path.isfile(args.collection):
44
+ ui_thread.print(ui_thread.PrinterText("Could not find the provided collection path, please provide with a valid collection path", ui_thread.PrinterText.WARNING))
45
+ return
46
+
47
+ collection_name = os.path.basename(args.collection)
48
+ docker_arguments += ["-c", collection_name]
49
+ mounts.append(pynt_container.create_mount(os.path.abspath(args.collection), "/etc/pynt/{}".format(collection_name)))
50
+
51
+ if "environment" in args and args.environment:
52
+ if not os.path.isfile(args.environment):
53
+ ui_thread.print(ui_thread.PrinterText("Could not find the provided environment path, please provide with a valid environment path", ui_thread.PrinterText.WARNING))
54
+ return
55
+
56
+ env_name = os.path.basename(args.environment)
57
+ docker_arguments += ["-e", env_name]
58
+ mounts.append(pynt_container.create_mount(os.path.abspath(args.environment), "/etc/pynt/{}".format(env_name)))
59
+
60
+ mounts.append(pynt_container.create_mount(CredStore().get_path(), "/app/creds.json"))
61
+
62
+ if "reporters" in args and args.reporters:
63
+ open(os.path.join(os.getcwd(), "results.json"), "w").close()
64
+ mounts.append(pynt_container.create_mount(os.path.join(os.getcwd(), "results.json"), "/etc/pynt/results/results.json"))
65
+ docker_arguments.append("--reporters")
66
+
67
+ if "insecure" in args and args.insecure:
68
+ docker_arguments.append("--insecure")
69
+
70
+ if "dev_flags" in args:
71
+ docker_arguments += args.dev_flags.split(" ")
72
+
73
+ newman_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
74
+ tag="latest",
75
+ detach=True,
76
+ mounts=mounts,
77
+ args=docker_arguments)
78
+
79
+ newman_docker.run(docker_type)
80
+ util.wait_for_healthcheck("http://localhost:{}".format(port))
81
+ ui_thread.print_generator(ui_thread.AnsiText.wrap_gen(newman_docker.stdout))
82
+
83
+ with ui_thread.progress(wrap_ws_progress(connect_progress_ws("ws://localhost:{}/progress".format(port))), "scan in progress..."):
84
+ while newman_docker.is_alive():
85
+ time.sleep(1)
@@ -0,0 +1,58 @@
1
+ import argparse
2
+ import time
3
+
4
+ from pyntcli.store.store import CredStore
5
+ from . import sub_command, util
6
+ from pyntcli.pynt_docker import pynt_container
7
+ from pyntcli.ui import ui_thread
8
+
9
+ def postman_usage():
10
+ return ui_thread.PrinterText("Integration with postman, run scan from pynt postman collection") \
11
+ .with_line("") \
12
+ .with_line("Usage:",style=ui_thread.PrinterText.HEADER) \
13
+ .with_line("\tpynt postman [OPTIONS]") \
14
+ .with_line("") \
15
+ .with_line("Options:",style=ui_thread.PrinterText.HEADER) \
16
+ .with_line("\t--port - set the port pynt will listen to (DEFAULT: 5001)") \
17
+ .with_line("\t--insecure - use when target uses self signed certificates")
18
+
19
+ class PostmanSubCommand(sub_command.PyntSubCommand):
20
+ def __init__(self, name) -> None:
21
+ super().__init__(name)
22
+
23
+ def usage(self, *args):
24
+ ui_thread.print(postman_usage())
25
+
26
+ def add_cmd(self, parent_command: argparse._SubParsersAction) -> argparse.ArgumentParser:
27
+ postman_cmd = parent_command.add_parser(self.name)
28
+ postman_cmd.add_argument("--port", "-p", help="set the port pynt will listen to (DEFAULT: 5001)", type=int, default=5001)
29
+ postman_cmd.print_usage = self.usage
30
+ postman_cmd.print_help = self.usage
31
+ return postman_cmd
32
+
33
+ def run_cmd(self, args: argparse.Namespace):
34
+ docker_type, docker_arguments = pynt_container.get_container_with_arguments(pynt_container.PyntDockerPort("5001", args.port, "--port"))
35
+
36
+ creds_path = CredStore().get_path()
37
+
38
+ if "insecure" in args and args.insecure:
39
+ docker_arguments.append("--insecure")
40
+
41
+ if "dev_flags" in args:
42
+ docker_arguments += args.dev_flags.split(" ")
43
+
44
+ if util.is_port_in_use(args.port):
45
+ ui_thread.print(ui_thread.PrinterText("Port: {} already in use, please use a different one".format(args.port), ui_thread.PrinterText.WARNING))
46
+ return
47
+
48
+ postman_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
49
+ tag="postman-latest",
50
+ mounts=[pynt_container.create_mount(creds_path, "/app/creds.json")],
51
+ detach=True,
52
+ args=docker_arguments)
53
+
54
+ postman_docker.run(docker_type)
55
+ ui_thread.print_generator(postman_docker.stdout)
56
+
57
+ while postman_docker.is_alive():
58
+ time.sleep(1)