pyntcli 0.1.99__py3-none-any.whl → 0.1.100__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,4 +1,4 @@
1
- __version__ = "0.1.99"
1
+ __version__ = "0.1.100"
2
2
 
3
3
  try:
4
4
  from logzio import sender
pyntcli/commands/burp.py CHANGED
@@ -227,15 +227,15 @@ class BurpCommand(sub_command.PyntSubCommand):
227
227
  return
228
228
 
229
229
  def run_cmd(self, args: argparse.Namespace):
230
- container = pynt_container.get_container_with_arguments(
231
- "proxy",
230
+ container_config = pynt_container.DockerContainerConfig(
232
231
  args,
232
+ "proxy",
233
233
  pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PORT, args.port, "--port"),
234
234
  pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PROXY_PORT, args.proxy_port, "--proxy-port"),
235
235
  )
236
236
 
237
237
  for host in args.captured_domains:
238
- container.docker_arguments += ["--host-targets", host]
238
+ container_config.docker_arguments += ["--host-targets", host]
239
239
 
240
240
  if "ca_path" in args and args.ca_path:
241
241
  if not os.path.isfile(args.ca_path):
@@ -248,14 +248,14 @@ class BurpCommand(sub_command.PyntSubCommand):
248
248
  return
249
249
 
250
250
  ca_name = os.path.basename(args.ca_path)
251
- container.docker_arguments += ["--ca-path", ca_name]
252
- container.mounts.append(
251
+ container_config.docker_arguments += ["--ca-path", ca_name]
252
+ container_config.mounts.append(
253
253
  pynt_container.create_mount(
254
254
  os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
255
255
  )
256
256
  )
257
257
 
258
- container.docker_arguments += ["--test-name", os.path.basename(args.xml)]
258
+ container_config.docker_arguments += ["--test-name", os.path.basename(args.xml)]
259
259
 
260
260
  if not os.path.isfile(args.xml):
261
261
  ui_thread.print(
@@ -286,12 +286,7 @@ class BurpCommand(sub_command.PyntSubCommand):
286
286
  )
287
287
  return
288
288
 
289
- proxy_docker = pynt_container.PyntContainer(
290
- image_name=pynt_container.PYNT_DOCKER_IMAGE,
291
- tag="v1-latest",
292
- detach=True,
293
- base_container=container,
294
- use_native=args.use_docker_native)
289
+ proxy_docker = pynt_container.PyntContainerNative(container_config)
295
290
 
296
291
  proxy_docker.prepare_client()
297
292
  proxy_docker.pre_run_validation(args.port)
@@ -145,19 +145,19 @@ class CommandSubCommand(sub_command.PyntSubCommand):
145
145
  return
146
146
 
147
147
  def run_cmd(self, args: argparse.Namespace):
148
- container = pynt_container.get_container_with_arguments(
149
- "proxy",
148
+ container_config = pynt_container.DockerContainerConfig(
150
149
  args,
150
+ "proxy",
151
151
  pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PORT, args.port, "--port"),
152
152
  pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PROXY_PORT, args.proxy_port, "--proxy-port"),
153
153
  )
154
154
 
155
155
  if args.captured_domains:
156
156
  for host in args.captured_domains:
157
- container.docker_arguments += ["--host-targets", host]
157
+ container_config.docker_arguments += ["--host-targets", host]
158
158
 
159
159
  if args.test_name:
160
- container.docker_arguments += ["--test-name", args.test_name]
160
+ container_config.docker_arguments += ["--test-name", args.test_name]
161
161
 
162
162
  if "ca_path" in args and args.ca_path:
163
163
  if not os.path.isfile(args.ca_path):
@@ -170,19 +170,14 @@ class CommandSubCommand(sub_command.PyntSubCommand):
170
170
  return
171
171
 
172
172
  ca_name = os.path.basename(args.ca_path)
173
- container.docker_arguments += ["--ca-path", ca_name]
174
- container.mounts.append(
173
+ container_config.docker_arguments += ["--ca-path", ca_name]
174
+ container_config.mounts.append(
175
175
  pynt_container.create_mount(
176
176
  os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
177
177
  )
178
178
  )
179
179
 
180
- proxy_docker = pynt_container.PyntContainer(
181
- image_name=pynt_container.PYNT_DOCKER_IMAGE,
182
- tag="v1-latest",
183
- detach=True,
184
- base_container=container,
185
- use_native=args.use_docker_native)
180
+ proxy_docker = pynt_container.PyntContainerNative(container_config)
186
181
 
187
182
  proxy_docker.prepare_client()
188
183
  proxy_docker.pre_run_validation(args.port)
pyntcli/commands/har.py CHANGED
@@ -58,8 +58,10 @@ class HarSubCommand(sub_command.PyntSubCommand):
58
58
  def run_cmd(self, args: argparse.Namespace):
59
59
  ui_thread.print_verbose("Building container")
60
60
  port = util.find_open_port()
61
- container = pynt_container.get_container_with_arguments(
62
- "har", args, pynt_container.PyntDockerPort(src=PYNT_CONTAINER_INTERNAL_PORT, dest=port, name="--port")
61
+ container_config = pynt_container.DockerContainerConfig(
62
+ args,
63
+ "har",
64
+ pynt_container.PyntDockerPort(src=PYNT_CONTAINER_INTERNAL_PORT, dest=port, name="--port")
63
65
  )
64
66
 
65
67
  if not os.path.isfile(args.har):
@@ -72,26 +74,21 @@ class HarSubCommand(sub_command.PyntSubCommand):
72
74
  return
73
75
 
74
76
  har_name = os.path.basename(args.har)
75
- container.docker_arguments += ["--har", har_name]
76
- container.mounts.append(
77
+ container_config.docker_arguments += ["--har", har_name]
78
+ container_config.mounts.append(
77
79
  pynt_container.create_mount(
78
80
  os.path.abspath(args.har), "/etc/pynt/{}".format(har_name)
79
81
  )
80
82
  )
81
83
 
82
84
  for host in args.captured_domains:
83
- container.docker_arguments += ["--host-targets", host]
85
+ container_config.docker_arguments += ["--host-targets", host]
84
86
 
85
87
  with util.create_default_file_mounts(args) as m:
86
88
 
87
- container.mounts += m
89
+ container_config.mounts += m
88
90
 
89
- har_docker = pynt_container.PyntContainer(
90
- image_name=pynt_container.PYNT_DOCKER_IMAGE,
91
- tag="v1-latest",
92
- detach=True,
93
- base_container=container,
94
- use_native=args.use_docker_native)
91
+ har_docker = pynt_container.PyntContainerNative(container_config)
95
92
 
96
93
  har_docker.prepare_client()
97
94
  har_docker.pre_run_validation(port)
@@ -106,17 +106,17 @@ class ListenSubCommand(sub_command.PyntSubCommand):
106
106
  return
107
107
 
108
108
  def run_cmd(self, args: argparse.Namespace):
109
- container = pynt_container.get_container_with_arguments(
110
- "proxy",
109
+ container_config = pynt_container.DockerContainerConfig(
111
110
  args,
111
+ "proxy",
112
112
  pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PORT, args.port, "--port"),
113
113
  pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PROXY_PORT, args.proxy_port, "--proxy-port"))
114
114
 
115
115
  for host in args.captured_domains:
116
- container.docker_arguments += ["--host-targets", host]
116
+ container_config.docker_arguments += ["--host-targets", host]
117
117
 
118
118
  if args.test_name:
119
- container.docker_arguments += ["--test-name", args.test_name]
119
+ container_config.docker_arguments += ["--test-name", args.test_name]
120
120
 
121
121
  if "ca_path" in args and args.ca_path:
122
122
  if not os.path.isfile(args.ca_path):
@@ -129,18 +129,14 @@ class ListenSubCommand(sub_command.PyntSubCommand):
129
129
  return
130
130
 
131
131
  ca_name = os.path.basename(args.ca_path)
132
- container.docker_arguments += ["--ca-path", ca_name]
133
- container.mounts.append(
132
+ container_config.docker_arguments += ["--ca-path", ca_name]
133
+ container_config.mounts.append(
134
134
  pynt_container.create_mount(
135
135
  os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
136
136
  )
137
137
  )
138
138
 
139
- proxy_docker = pynt_container.PyntContainer(
140
- image_name=pynt_container.PYNT_DOCKER_IMAGE,
141
- tag="v1-latest",
142
- detach=True,
143
- base_container=container)
139
+ proxy_docker = pynt_container.PyntContainerNative(container_config)
144
140
 
145
141
  proxy_docker.prepare_client()
146
142
  proxy_docker.pre_run_validation(args.port)
@@ -57,8 +57,10 @@ class NewmanSubCommand(sub_command.PyntSubCommand):
57
57
  def run_cmd(self, args: argparse.Namespace):
58
58
 
59
59
  port = util.find_open_port()
60
- container = pynt_container.get_container_with_arguments(
61
- "newman", args, pynt_container.PyntDockerPort(src=PYNT_CONTAINER_INTERNAL_PORT, dest=port, name="--port")
60
+ container_config = pynt_container.DockerContainerConfig(
61
+ args,
62
+ "newman",
63
+ pynt_container.PyntDockerPort(src=PYNT_CONTAINER_INTERNAL_PORT, dest=port, name="--port")
62
64
  )
63
65
 
64
66
  if not os.path.isfile(args.collection):
@@ -71,8 +73,8 @@ class NewmanSubCommand(sub_command.PyntSubCommand):
71
73
  return
72
74
 
73
75
  collection_name = os.path.basename(args.collection)
74
- container.docker_arguments += ["-c", collection_name]
75
- container.mounts.append(
76
+ container_config.docker_arguments += ["-c", collection_name]
77
+ container_config.mounts.append(
76
78
  pynt_container.create_mount(
77
79
  os.path.abspath(args.collection), "/etc/pynt/{}".format(collection_name)
78
80
  )
@@ -91,21 +93,16 @@ class NewmanSubCommand(sub_command.PyntSubCommand):
91
93
  return
92
94
  env_name = os.path.basename(environ)
93
95
  env_names.append(env_name)
94
- container.mounts.append(
96
+ container_config.mounts.append(
95
97
  pynt_container.create_mount(
96
98
  os.path.abspath(environ), "/etc/pynt/{}".format(env_name)
97
99
  )
98
100
  )
99
- container.docker_arguments += ["-e", ",".join(env_names)]
101
+ container_config.docker_arguments += ["-e", ",".join(env_names)]
100
102
 
101
103
  with util.create_default_file_mounts(args) as m:
102
- container.mounts += m
103
- newman_docker = pynt_container.PyntContainer(
104
- image_name=pynt_container.PYNT_DOCKER_IMAGE,
105
- tag="v1-latest",
106
- detach=True,
107
- base_container=container,
108
- use_native=args.use_docker_native)
104
+ container_config.mounts += m
105
+ newman_docker = pynt_container.PyntContainerNative(container_config)
109
106
 
110
107
  newman_docker.prepare_client()
111
108
  newman_docker.pre_run_validation(port)
@@ -95,13 +95,12 @@ class PostmanSubCommand(sub_command.PyntSubCommand):
95
95
  ui_thread.print("application-id is not supported in postman integration, use the collection variables to set application id.")
96
96
  args.application_id = ""
97
97
 
98
- container = pynt_container.get_container_with_arguments("postman", args, pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PORT, args.port, name="--port"))
98
+ container_config = pynt_container.DockerContainerConfig(
99
+ args,
100
+ "postman",
101
+ pynt_container.PyntDockerPort(PYNT_CONTAINER_INTERNAL_PORT, args.port, name="--port"))
99
102
 
100
- postman_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
101
- tag="v1-latest",
102
- detach=True,
103
- base_container=container,
104
- use_native=args.use_docker_native)
103
+ postman_docker = pynt_container.PyntContainerNative(container_config)
105
104
  postman_docker.prepare_client()
106
105
  postman_docker.pre_run_validation(args.port)
107
106
  postman_docker.run()
pyntcli/commands/root.py CHANGED
@@ -88,7 +88,14 @@ class BaseCommand:
88
88
  parser.add_argument(
89
89
  "--use-docker-native",
90
90
  action="store_true",
91
- help="Use native docker instead of docker sdk"
91
+ help=argparse.SUPPRESS,
92
+ )
93
+ parser.add_argument(
94
+ "--pynt-image",
95
+ default="",
96
+ required=False,
97
+ type=str,
98
+ help=argparse.SUPPRESS,
92
99
  )
93
100
 
94
101
  def get_subparser(self) -> argparse._SubParsersAction:
pyntcli/main.py CHANGED
@@ -32,14 +32,6 @@ def signal_handler(signal_number, frame):
32
32
 
33
33
  exit(0)
34
34
 
35
-
36
- def get_docker_platform_name(use_docker_native: bool = False) -> str:
37
- if use_docker_native:
38
- return pynt_container.get_docker_platform_by_native_command()
39
-
40
- return pynt_container.get_docker_platform_by_sdk()
41
-
42
-
43
35
  def print_header():
44
36
  ui_thread.print(ui_thread.PrinterText(*ui_thread.pynt_header())
45
37
  .with_line(*ui_thread.pynt_version())
@@ -79,16 +71,12 @@ def main():
79
71
  if "--verbose" in argv:
80
72
  ui_thread.VERBOSE = True
81
73
 
82
- use_docker_native = True if "--use-docker-native" in argv else False
83
- if use_docker_native:
84
- analytics.emit(analytics.DOCKER_NATIVE_FLAG, {"message": "using docker native flag"})
85
-
86
74
  log.set_source(__version__)
87
75
  ui_thread.print_verbose("Logging in...")
88
76
  user_id = login.user_id()
89
77
  start_analytics(user_id)
90
78
  ui_thread.print_verbose("Asserting docker is properly installed")
91
- platform_name = get_docker_platform_name(use_docker_native)
79
+ platform_name = pynt_container.get_docker_platform_name()
92
80
  ui_thread.print_verbose("Docker platform: {}".format(platform_name))
93
81
  signal.signal(signal.SIGINT, signal_handler)
94
82
  cli = pynt_cmd.PyntCommand()
@@ -1,8 +1,5 @@
1
1
  import platform
2
2
  import subprocess
3
- import docker
4
- from docker.errors import DockerException, APIError, ImageNotFound
5
- from requests.exceptions import ReadTimeout
6
3
  from docker.types import Mount
7
4
  import os
8
5
  import json
@@ -46,7 +43,7 @@ class PortInUseException(Exception):
46
43
  super().__init__(self.message)
47
44
 
48
45
 
49
- def get_docker_platform_by_native_command():
46
+ def get_docker_platform_name():
50
47
  try:
51
48
  version_data = json.loads(subprocess.check_output(["docker", "version", "--format", "{{json .}}"], text=True))
52
49
  platform = version_data.get("Server", {}).get("Platform", {})
@@ -56,23 +53,6 @@ def get_docker_platform_by_native_command():
56
53
  raise DockerNotAvailableException()
57
54
 
58
55
 
59
- def get_docker_platform_by_sdk():
60
- try:
61
- c = docker.from_env()
62
- version_data = c.version()
63
- platform = version_data.get("Platform")
64
- analytics.deferred_emit(analytics.DOCKER_PLATFORM, platform)
65
- if platform and platform.get("Name"):
66
- return platform.get("Name")
67
-
68
- return ""
69
-
70
- except DockerException:
71
- raise DockerNotAvailableException()
72
- except Exception: # TODO: This is since windows is not behaving nice
73
- raise DockerNotAvailableException()
74
-
75
-
76
56
  class PyntBaseContainer():
77
57
  def __init__(self, docker_type, docker_arguments, mounts, environment={}) -> None:
78
58
  self.docker_type = docker_type
@@ -88,33 +68,83 @@ class PyntDockerPort:
88
68
  self.name = name
89
69
 
90
70
 
91
- def is_network_host(use_docker_sdk: bool) -> bool:
71
+ class PyntDockerImage:
72
+ def __init__(self, name, is_self_managed) -> None:
73
+ self.name = name
74
+ self.is_self_managed = is_self_managed
75
+
76
+
77
+ class DockerContainerConfig:
78
+ def __init__(self, args: argparse.Namespace, integration_name: str, *port_args: PyntDockerPort):
79
+ self.image = get_image_config(args)
80
+ self.is_detach = True
81
+ self.ports = port_args
82
+ self.docker_arguments = build_docker_args(integration_name, args)
83
+ self.mounts = get_docker_mounts(args)
84
+ self.env_vars = {PYNT_ID: CredStore().get_tokens(), "PYNT_SAAS_URL": PYNT_SAAS}
85
+ if user_set_all_variables():
86
+ add_env_variables(self.env_vars)
87
+
88
+ ports = {}
89
+ create_network_host = is_network_host()
90
+ for p in port_args:
91
+ if create_network_host:
92
+ self.docker_arguments.append(p.name)
93
+ self.docker_arguments.append(str(p.dest))
94
+ else:
95
+ ports[str(p.src)] = int(p.dest)
96
+
97
+ if create_network_host:
98
+ self.docker_type = PyntNativeHost(network="host")
99
+ else:
100
+ self.docker_type = PyntDockerDesktopContainer(ports=ports)
101
+
102
+
103
+ def get_image_config(args: argparse.Namespace) -> PyntDockerImage:
104
+ default_image = f'{PYNT_DOCKER_IMAGE}:v1-latest'
105
+ if "pynt_image" in args and args.pynt_image:
106
+ return PyntDockerImage(args.pynt_image, True)
107
+ env_name = value_from_environment_variable("IMAGE")
108
+ env_tag = value_from_environment_variable("TAG")
109
+ if env_name:
110
+ return PyntDockerImage(f'{env_name}:{env_tag}', True)
111
+
112
+ return PyntDockerImage(default_image, False)
113
+
114
+
115
+ def is_network_host() -> bool:
92
116
  platform_sys_name = platform.system()
93
117
  if platform_sys_name == "Windows" or platform_sys_name == "Darwin":
94
118
  return False
95
119
  else:
96
- docker_platform_name = get_docker_platform_by_sdk().lower() if use_docker_sdk else get_docker_platform_by_native_command().lower()
120
+ docker_platform_name = get_docker_platform_name().lower()
97
121
  if "desktop" in docker_platform_name:
98
122
  return False
99
123
  return True
100
124
 
101
125
 
102
- def get_container_with_arguments(integration: str, args: argparse.Namespace, *port_args: PyntDockerPort) \
103
- -> PyntBaseContainer:
104
- docker_arguments = [integration]
105
- ports = {}
106
- create_network_host = is_network_host(args.use_docker_native)
107
- for p in port_args:
108
- if create_network_host:
109
- docker_arguments.append(p.name)
110
- docker_arguments.append(str(p.dest))
111
- else:
112
- ports[str(p.src)] = int(p.dest)
126
+ def user_set_all_variables():
127
+ return all([PYNT_BUCKET_NAME, PYNT_PARAM1, PYNT_PARAM2])
128
+
129
+
130
+ def add_env_variables(env: dict):
131
+ env["PYNT_BUCKET_NAME"] = PYNT_BUCKET_NAME
132
+ env["PYNT_PARAM1"] = base64.b64encode(PYNT_PARAM1.encode('utf-8'))
133
+ env["PYNT_PARAM2"] = base64.b64encode(PYNT_PARAM2.encode('utf-8'))
134
+
135
+
136
+ def value_from_environment_variable(key):
137
+ e = os.environ.get(key)
138
+
139
+ if e:
140
+ ui_thread.print_verbose(f"Using environment variable {key}={e}")
141
+ return e
142
+
143
+ return None
113
144
 
114
- if create_network_host:
115
- docker_type = PyntNativeContainer(network="host")
116
- else:
117
- docker_type = PyntDockerDesktopContainer(ports=ports)
145
+
146
+ def build_docker_args(integration_name:str, args: argparse.Namespace) -> list[str]:
147
+ docker_arguments = [integration_name]
118
148
 
119
149
  if "insecure" in args and args.insecure:
120
150
  docker_arguments.append("--insecure")
@@ -128,73 +158,46 @@ def get_container_with_arguments(integration: str, args: argparse.Namespace, *po
128
158
  if "dev_flags" in args:
129
159
  docker_arguments += args.dev_flags.split(" ")
130
160
 
131
- mounts = []
132
161
  if "host_ca" in args and args.host_ca:
133
162
  ca_name = os.path.basename(args.host_ca)
134
163
  docker_arguments += ["--host-ca", ca_name]
135
- mounts.append(create_mount(os.path.abspath(args.host_ca), "/etc/pynt/{}".format(ca_name)))
136
164
 
137
165
  if "transport_config" in args and args.transport_config:
138
166
  tc_name = os.path.basename(args.transport_config)
139
167
  docker_arguments += ["--transport-config", tc_name]
140
- mounts.append(create_mount(os.path.abspath(args.transport_config), "/etc/pynt/{}".format(tc_name)))
141
168
 
142
169
  if "verbose" in args and args.verbose:
143
170
  docker_arguments.append("--verbose")
144
171
 
145
- creds_path = os.path.dirname(CredStore().file_location)
146
- mitm_cert_path = os.path.join(creds_path, "cert")
147
- os.makedirs(mitm_cert_path, exist_ok=True)
148
- mounts.append(create_mount(mitm_cert_path, "/root/.mitmproxy"))
149
-
150
- env = {PYNT_ID: CredStore().get_tokens(), "PYNT_SAAS_URL": PYNT_SAAS}
151
- if user_set_all_variables():
152
- add_env_variables(env)
153
- return PyntBaseContainer(docker_type, docker_arguments, mounts, env)
154
-
172
+ return docker_arguments
155
173
 
156
- def _container_image_from_tag(tag: str) -> str:
157
- if ":" in tag:
158
- return tag.split(":")[0]
159
-
160
- return tag
161
-
162
-
163
- def user_set_all_variables():
164
- return all([PYNT_BUCKET_NAME, PYNT_PARAM1, PYNT_PARAM2])
165
-
166
-
167
- def add_env_variables(env: dict):
168
- env["PYNT_BUCKET_NAME"] = PYNT_BUCKET_NAME
169
- env["PYNT_PARAM1"] = base64.b64encode(PYNT_PARAM1.encode('utf-8'))
170
- env["PYNT_PARAM2"] = base64.b64encode(PYNT_PARAM2.encode('utf-8'))
171
174
 
175
+ def get_docker_mounts(args: argparse.Namespace) -> list:
176
+ mounts = []
177
+ if "host_ca" in args and args.host_ca:
178
+ ca_name = os.path.basename(args.host_ca)
179
+ mounts.append(create_mount(os.path.abspath(args.host_ca), "/etc/pynt/{}".format(ca_name)))
172
180
 
173
- def value_from_environment_variable(key, fallback=""):
174
- e = os.environ.get(key)
181
+ if "transport_config" in args and args.transport_config:
182
+ tc_name = os.path.basename(args.transport_config)
183
+ mounts.append(create_mount(os.path.abspath(args.transport_config), "/etc/pynt/{}".format(tc_name)))
175
184
 
176
- if e:
177
- ui_thread.print_verbose(f"Using environment variable {key}={e}")
178
- return e
179
- if fallback != "":
180
- ui_thread.print_verbose(f"Using variable {key}={fallback}")
181
- return fallback
185
+ return mounts
182
186
 
183
187
 
184
188
  class PyntContainerNative:
185
- def __init__(self, image_name, tag, base_container, is_detach=True):
186
- self.image_name = value_from_environment_variable("IMAGE", image_name)
187
- self.tag = value_from_environment_variable("TAG", tag)
188
- self.is_detach = is_detach
189
- self.mounts = base_container.mounts
190
- self.env_vars = base_container.environment
191
- self.base_container = base_container
189
+ def __init__(self, container_config: DockerContainerConfig):
190
+ self.config = container_config
192
191
  self.container_name = ""
193
192
  self.system = platform.system().lower()
194
-
195
193
  self.stdout = None
196
194
  self.running = False
197
195
 
196
+ creds_path = os.path.dirname(CredStore().file_location)
197
+ mitm_cert_path = os.path.join(creds_path, "cert")
198
+ os.makedirs(mitm_cert_path, exist_ok=True)
199
+ self.config.mounts.append(create_mount(mitm_cert_path, "/root/.mitmproxy"))
200
+
198
201
  def is_alive(self):
199
202
  command = ["docker", "ps", "--filter", f"name={self.container_name}", "--filter", "status=running"]
200
203
  result = subprocess.run(
@@ -211,23 +214,20 @@ class PyntContainerNative:
211
214
  def run(self):
212
215
  self.running = True
213
216
 
214
- self.get_image()
215
- args = self.base_container.docker_arguments if self.base_container.docker_arguments else None
216
- docker_command = ["docker", "run"]
217
-
218
- if self.is_detach:
219
- docker_command.append("-d")
217
+ self.fetch_and_validate_image()
218
+ args = self.config.docker_arguments if self.config.docker_arguments else None
219
+ docker_command = ["docker", "run", "-d"]
220
220
 
221
221
  mounts = []
222
- for mount in self.base_container.mounts:
222
+ for mount in self.config.mounts:
223
223
  mounts.extend(["-v", f"{mount['Source']}:{mount['Target']}"])
224
224
 
225
225
  env_vars = []
226
- for key, value in self.base_container.environment.items():
226
+ for key, value in self.config.env_vars.items():
227
227
  env_vars.extend(self.adapt_environment_variable_partial(key, value))
228
228
 
229
229
  docker_type_options = []
230
- for key, value in self.base_container.docker_type.get_arguments().items():
230
+ for key, value in self.config.docker_type.get_arguments().items():
231
231
  if key == "ports":
232
232
  if isinstance(value, dict):
233
233
  for s, d in value.items():
@@ -239,10 +239,11 @@ class PyntContainerNative:
239
239
  docker_command += mounts
240
240
  docker_command += env_vars
241
241
  docker_command += docker_type_options
242
- docker_command += [f"{self.image_name}:{self.tag}"]
242
+ docker_command += [f"{self.config.image.name}"]
243
243
  docker_command += args
244
244
 
245
245
  command = self.adapt_run_command(docker_command)
246
+ PyntContainerRegistry.instance().register_container(self)
246
247
  process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
247
248
  stdout, stderr = process.communicate()
248
249
 
@@ -268,8 +269,8 @@ class PyntContainerNative:
268
269
  def kill_other_instances(self, report_to_user=True):
269
270
  ui_thread.print_verbose("Killing other pynt containers if such exist")
270
271
  try:
271
- for tag in IMAGE_TAGS:
272
- command = ["docker", "ps", "-q", "-f", f"ancestor={self.image_name}:{tag}"]
272
+ for _ in IMAGE_TAGS:
273
+ command = ["docker", "ps", "-q", "-f", f"ancestor={self.config.image.name}"]
273
274
  containers_output = subprocess.check_output(command, text=True)
274
275
  if not containers_output:
275
276
  continue
@@ -286,41 +287,28 @@ class PyntContainerNative:
286
287
  analytics.emit(analytics.ERROR, {"error": "Unable to kill other pynt containers"})
287
288
  ui_thread.print(ui_thread.PrinterText("Error: Unable to kill other pynt containers", ui_thread.PrinterText.WARNING))
288
289
 
289
- def pull_image(self):
290
- try:
291
- command = ["docker", "pull", f"{self.image_name}:{self.tag}"]
292
- subprocess.run(command, capture_output=True, text=True)
293
- except subprocess.CalledProcessError:
294
- analytics.emit(analytics.ERROR, {"error": "Unable to pull image from ghcr"})
295
- ui_thread.print(ui_thread.PrinterText("Error: Docker unable to pull latest Pynt image due to VPN/proxy. If using a mirror for Docker images, visit docs.pynt.io for help.", ui_thread.PrinterText.WARNING))
296
- return None
297
-
298
- def get_image(self):
290
+ def fetch_and_validate_image(self):
299
291
  try:
300
292
  ui_thread.print(ui_thread.PrinterText("Pulling latest docker image", ui_thread.PrinterText.INFO))
301
- command = ['docker', 'pull', f'{self.image_name}:{self.tag}']
302
- process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
303
- stdout, stderr = process.communicate()
304
-
305
- if process.returncode != 0:
306
- raise ImageUnavailableException(f"Failed to pull image: {stderr.decode().strip()}")
307
-
308
- command = ['docker', 'images', '-q', f'{self.image_name}']
309
- process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
310
- stdout, stderr = process.communicate()
311
-
312
- stdout = stdout.decode('utf-8')
313
- stderr = stderr.decode('utf-8')
314
-
315
- if stderr:
316
- ui_thread.print(ui_thread.PrinterText(f"Error: {stderr}", ui_thread.PrinterText.WARNING))
293
+ pull_command = ['docker', 'pull', self.config.image.name]
294
+ get_image_command = ['docker', 'images', '-q', f'{self.config.image.name}']
295
+ pull_process = subprocess.Popen(pull_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
296
+ pull_stdout, pull_stderr = pull_process.communicate()
297
+ get_process = subprocess.Popen(get_image_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
298
+ get_stdout, _ = get_process.communicate()
299
+ local_image_id = get_stdout.decode('utf-8')
300
+ if self.config.image.is_self_managed and local_image_id:
301
+ return local_image_id.strip()
302
+ elif local_image_id == "":
303
+ ui_thread.print(ui_thread.PrinterText(f"Error: the image {self.config.image.name} not found",
304
+ ui_thread.PrinterText.WARNING))
305
+ raise ImageUnavailableException("Failed to find local image")
306
+ if pull_stderr and local_image_id == "":
307
+ ui_thread.print(ui_thread.PrinterText(f"Error: {pull_stderr}", ui_thread.PrinterText.WARNING))
317
308
  raise ImageUnavailableException("Failed to pull image")
318
309
 
319
- if process.returncode != 0:
310
+ if pull_process.returncode != 0:
320
311
  raise ImageUnavailableException("Failed to pull image")
321
-
322
- image_id = stdout.strip()
323
- return image_id
324
312
  except Exception as e:
325
313
  raise ImageUnavailableException(f"An error occurred: {str(e)}")
326
314
 
@@ -340,169 +328,12 @@ class PyntContainerNative:
340
328
  return ["-e", f"{key}={json.dumps(value)}"]
341
329
  return ["-e", f"{key}={value}"]
342
330
 
343
-
344
- class PyntContainerSDK:
345
- def __init__(self, image_name, tag, base_container, is_detach=True) -> None:
346
- self.image_name = value_from_environment_variable("IMAGE", image_name)
347
- self.tag = value_from_environment_variable("TAG", tag)
348
- self.base_container = base_container
349
- self.is_detach = is_detach
350
-
351
- self.mounts = base_container.mounts
352
- self.env_vars = base_container.environment
353
-
354
- self.docker_client: docker.DockerClient = None
355
- self.container_name = ""
356
- self.stdout = None
357
- self.running = False
358
- self.system = platform.system().lower()
359
-
360
- def _initialize(self):
361
- self.docker_client = docker.from_env()
362
- docker_password = value_from_environment_variable("DOCKER_PASSWORD")
363
- docker_username = value_from_environment_variable("DOCKER_USERNAME")
364
- docker_registry = value_from_environment_variable("DOCKER_REGISTRY")
365
- if docker_password and docker_username and docker_registry:
366
- self.docker_client.login(username=docker_username, password=docker_password, registry=docker_registry)
367
-
368
- def is_alive(self):
369
- if not self.docker_client or not self.container_name:
370
- return False
371
-
372
- l = self.docker_client.containers.list(filters={"name": self.container_name})
373
- if len(l) != 1:
374
- return False
375
-
376
- return l[0].status == "running"
377
-
378
- def prepare_client(self):
379
- if not self.docker_client:
380
- self._initialize()
381
-
382
- def run(self):
383
- if not self.docker_client:
384
- self._initialize()
385
-
386
- self.running = True
387
-
388
- image = self.get_image()
389
- ui_thread.print(ui_thread.PrinterText("Docker pull done", ui_thread.PrinterText.INFO))
390
-
391
- args = self.base_container.docker_arguments if self.base_container.docker_arguments else None
392
-
393
- run_arguments = {
394
- "image": image,
395
- "detach": self.is_detach,
396
- "mounts": self.base_container.mounts,
397
- "environment": self.base_container.environment,
398
- "stream": True,
399
- "remove": True,
400
- "command": args
401
- }
402
-
403
- run_arguments.update(self.base_container.docker_type.get_arguments())
404
-
405
- ui_thread.print_verbose("Running pynt docker with arguments:\n {}".format(" ".join(args)))
406
- c = self.docker_client.containers.run(**run_arguments)
407
- self.container_name = c.name
408
- self.stdout = c.logs(stream=True)
409
-
410
- def kill_other_instances(self, report_to_user=True):
411
- for c in self.docker_client.containers.list():
412
- if len(c.image.tags) and _container_image_from_tag(c.image.tags[0]) == self.image_name:
413
- c.kill()
414
- self.wait_for_container_end(c)
415
- if report_to_user:
416
- ui_thread.print(ui_thread.PrinterText("Another Pynt container was running, killed it", ui_thread.PrinterText))
417
-
418
- def wait_for_container_end(self, container):
419
- # only windows kill is require a wait for the container to stop, otherwise the port stays in use
420
- if self.system != "windows":
421
- return
422
- try:
423
- container.wait(timeout=10)
424
- except ReadTimeout: # container is still running
425
- ui_thread.print(
426
- ui_thread.PrinterText("Timeout reached while waiting for container to stop", ui_thread.PrinterText))
427
- except APIError: # container is already stopped
428
- pass
429
-
430
- def pull_image(self):
431
- try:
432
- return self.docker_client.images.pull(self.image_name, tag=self.tag)
433
- except APIError as e:
434
- analytics.emit(analytics.ERROR, {"error": "Unable to pull image from ghcr: {}".format(e)})
435
- ui_thread.print(ui_thread.PrinterText("Error: Docker unable to pull latest Pynt image due to VPN/proxy. Visit docs.pynt.io for help using a mirror for Docker images.", ui_thread.PrinterText.WARNING))
436
- return None
437
-
438
- def get_image(self):
439
- ui_thread.print(ui_thread.PrinterText("Pulling latest docker image", ui_thread.PrinterText.INFO))
440
- try:
441
- image = self.pull_image()
442
- if not image:
443
- ui_thread.print(ui_thread.PrinterText("Trying to get pynt local image", ui_thread.PrinterText.INFO))
444
- image = self.docker_client.images.get(f"{self.image_name}:{self.tag}")
445
- return image
446
- except ImageNotFound:
447
- raise ImageUnavailableException()
448
-
449
- def stop(self):
450
- if not self.running:
451
- return
452
- self.kill_other_instances(report_to_user=False)
453
- self.docker_client.close()
454
- self.docker_client = None
455
- self.running = False
456
-
457
-
458
- class PyntContainer:
459
- def __init__(self, image_name, tag, detach, base_container: PyntBaseContainer, use_native=False) -> None:
460
- self.use_native = use_native
461
-
462
- if use_native:
463
- self.client_implementation = PyntContainerNative(image_name=image_name, tag=tag, base_container=base_container, is_detach=detach)
464
- else:
465
- self.client_implementation = PyntContainerSDK(image_name=image_name, tag=tag, base_container=base_container, is_detach=detach)
466
-
467
- self.image = image_name
468
- self.tag = tag
469
- self.detach = detach
470
- self.container_name = ""
471
- self.base_container = base_container
472
- self.stdout = None
473
-
474
- def kill_other_instances(self):
475
- self.client_implementation.kill_other_instances()
476
-
477
- def stop(self):
478
- self.client_implementation.stop()
479
-
480
- def is_alive(self):
481
- return self.client_implementation.is_alive()
482
-
483
- def pull_image(self):
484
- return self.client_implementation.pull_image()
485
-
486
- def get_image(self):
487
- return self.client_implementation.get_image()
488
-
489
- def run(self):
490
- self.client_implementation.run()
491
- self.stdout = self.client_implementation.stdout
492
- PyntContainerRegistry.instance().register_container(self)
493
-
494
331
  def pre_run_validation(self, port):
495
332
  self.kill_other_instances()
496
333
 
497
334
  if container_utils.is_port_in_use(int(port)):
498
335
  raise PortInUseException(port)
499
336
 
500
- def prepare_client(self):
501
- self.client_implementation.prepare_client()
502
-
503
- def running(self):
504
- return self.client_implementation.running
505
-
506
337
 
507
338
  class PyntDockerDesktopContainer:
508
339
  def __init__(self, ports) -> None:
@@ -512,7 +343,7 @@ class PyntDockerDesktopContainer:
512
343
  return {"ports": self.ports} if self.ports else {}
513
344
 
514
345
 
515
- class PyntNativeContainer:
346
+ class PyntNativeHost:
516
347
  def __init__(self, network) -> None:
517
348
  self.network = network
518
349
 
@@ -524,7 +355,7 @@ class PyntContainerRegistry:
524
355
  _instance = None
525
356
 
526
357
  def __init__(self) -> None:
527
- self.containers: List[PyntContainer] = []
358
+ self.containers: List[PyntContainerNative] = []
528
359
 
529
360
  @staticmethod
530
361
  def instance():
@@ -533,7 +364,7 @@ class PyntContainerRegistry:
533
364
 
534
365
  return PyntContainerRegistry._instance
535
366
 
536
- def register_container(self, c: PyntContainer):
367
+ def register_container(self, c: PyntContainerNative):
537
368
  self.containers.append(c)
538
369
 
539
370
  def stop_all_containers(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyntcli
3
- Version: 0.1.99
3
+ Version: 0.1.100
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=KFlzWhXBAuwdi7GXf16gCB3ya94LQG2wjcSChE149rQ,3798
3
3
  ignoreTests/store/cred_store.py,sha256=_7-917EtNC9eKEumO2_lt-7KuDmCwOZFaowCm7DbA_A,254
4
- pyntcli/__init__.py,sha256=96CSieH-K5R3B_CG2Gfc3dNu3WA01VqXDKUfJ__2Pdg,402
5
- pyntcli/main.py,sha256=-INlAS5ks6ofT38Nap0FylRYjCdrLZLuTn5-Pea5UXY,6528
4
+ pyntcli/__init__.py,sha256=-ZeumLDPTHS2r0t8ZT98JHgmzaxmfZaDpjbaLrfkeuw,403
5
+ pyntcli/main.py,sha256=WEbWyqzDjtnZGSWgqru1FCT7wmHdi11uzd1LmwTTCI4,6095
6
6
  pyntcli/analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  pyntcli/analytics/send.py,sha256=9TRAEoPbv4rWOZfcNaGanrRJAFvNs39P-uKSl49GcQE,3679
8
8
  pyntcli/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  pyntcli/auth/login.py,sha256=TljsRXbEkNI1YUrKm5mlTw4YiecYScYUsit8Z8vstss,5228
10
10
  pyntcli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- pyntcli/commands/burp.py,sha256=z6_kYEL6cXNg5yFFR4d8UAgJGTLn3XgUNWsqCBhsJoE,12398
12
- pyntcli/commands/command.py,sha256=Aw2wb4pV99r9ot6gC2ckqg_1379PZLfudQZ3Igx8Lds,11143
13
- pyntcli/commands/har.py,sha256=YekPhsbIuuw_lNby97CPDNkEJysFycr_cx-8nPTX6Co,4470
11
+ pyntcli/commands/burp.py,sha256=5lZKSDHJvmVNvxEkQPKQ4lNx8pSzEK-rTHhSvn-ZBtY,12253
12
+ pyntcli/commands/command.py,sha256=7x5eGXGz1rHtAy-Shdh3KLIqQ7TVAZEKd5DiKaCLOSQ,10998
13
+ pyntcli/commands/har.py,sha256=NzxyXlgS5YtQJqi9528V0FkbonMaZ0wHuvRl0LmR5JA,4329
14
14
  pyntcli/commands/id_command.py,sha256=UBEgMIpm4vauTCsKyixltiGUolNg_OfHEJvJ_i5BpJY,943
15
- pyntcli/commands/listen.py,sha256=UERWRArlJQGbM9-bZzG4OlDD7r73UxdwHFWWzxkNObE,9081
16
- pyntcli/commands/newman.py,sha256=n1eNjeE6dEPjq9Sax9MXcZCJLzn29MidLjV2GeVYmPU,5307
17
- pyntcli/commands/postman.py,sha256=b_nF-ryleENUrr1RzqmzhJmhWR4IWPw0ehS9y_11m4U,5262
15
+ pyntcli/commands/listen.py,sha256=oxgMvJYpPEu6h8qRFoueGF3a_nmwzaWMPL8ucfy7yxE,8983
16
+ pyntcli/commands/newman.py,sha256=PRbsbDTxL54FRVYOYEpKJ5icVdGXtG2bfiGsnJgmKT4,5173
17
+ pyntcli/commands/postman.py,sha256=HPFNcmAtVziLCAimUg8GUXBMUGBGAXBrSPvP6Tuiubk,4971
18
18
  pyntcli/commands/pynt_cmd.py,sha256=T7jee0yw67Zth3lTkSDInCLnbu_IhpNqb7GqnTiTceQ,7012
19
- pyntcli/commands/root.py,sha256=4yeGlTeL3Xu2xlSbMYhhaDwUnP29sF2Y2sxq8E1P3lo,3986
19
+ pyntcli/commands/root.py,sha256=6dSzKSjUX-ZetE2KYJNkBmfDDrcYJligmHBqIAIc2aQ,4140
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/util.py,sha256=csZHQ2Xbdh-_KX-yIVrnaeNsT0NbuS-ej6kND3CxD_w,4414
@@ -24,7 +24,7 @@ pyntcli/log/__init__.py,sha256=cOGwOYzMoshEbZiiasBGkj6wF0SBu3Jdpl-AuakDesw,19
24
24
  pyntcli/log/log.py,sha256=cWCdWmUaAwePwdhYDcgNMEG9d9RM34sGahxBCYEdv2Y,1069
25
25
  pyntcli/pynt_docker/__init__.py,sha256=PQIOVxc7XXtMLfEX7ojgwf_Z3mmTllO3ZvzUZTPOxQY,30
26
26
  pyntcli/pynt_docker/container_utils.py,sha256=_Onn7loInzyJAG2-Uk6CGpsuRyelmUFHOvtJj4Uzi9A,175
27
- pyntcli/pynt_docker/pynt_container.py,sha256=Fbm03hofQR7F5_wQaJ2NgEjBE8TvYE7_fv5K_ps4y7M,19499
27
+ pyntcli/pynt_docker/pynt_container.py,sha256=NxizyjSgXSyPbKFs5ggyBSOcLVlb0xk9MS96L2XLrZ4,13126
28
28
  pyntcli/store/__init__.py,sha256=1fP8cEAQCF_myja3gnhHH9FEqtBiOJ-2aBmUXSKBdFA,41
29
29
  pyntcli/store/json_connector.py,sha256=UGs3uORw3iyn0YJ8kzab-veEZToA6d-ByXYuqEleWsA,560
30
30
  pyntcli/store/store.py,sha256=ZLSe0WAjHDp8cSt4BBFDkPGRux4cgOo5UfF7V4naM7U,2559
@@ -39,8 +39,8 @@ pyntcli/ui/report.py,sha256=W-icPSZrGLOubXgam0LpOvHLl_aZg9Zx9qIkL8Ym5PE,1930
39
39
  pyntcli/ui/ui_thread.py,sha256=XUBgLpYQjVhrilU-ofw7VSXgTiwneSdTxm61EvC3x4Q,5091
40
40
  tests/test_utils.py,sha256=t5fTQUk1U_Js6iMxcGYGqt4C-crzOJ0CqCKtLkRtUi0,2050
41
41
  tests/commands/test_pynt_cmd.py,sha256=BjGFCFACcSziLrNA6_27t6TjSmvdu54wx9njwLpRSJY,8379
42
- pyntcli-0.1.99.dist-info/METADATA,sha256=6jNnyPGykzIJa0hDpAMadLZYm3FznLEz5g8Th7n2wF0,493
43
- pyntcli-0.1.99.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
44
- pyntcli-0.1.99.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
45
- pyntcli-0.1.99.dist-info/top_level.txt,sha256=64XSgBzSpgwjYjEKHZE7q3JH2a816zEeyZBXfJi3AKI,42
46
- pyntcli-0.1.99.dist-info/RECORD,,
42
+ pyntcli-0.1.100.dist-info/METADATA,sha256=ofzCKRvESAbl7zbATZPp-PCqCJT-EP_3xPNRPj_3i0E,494
43
+ pyntcli-0.1.100.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
44
+ pyntcli-0.1.100.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
45
+ pyntcli-0.1.100.dist-info/top_level.txt,sha256=64XSgBzSpgwjYjEKHZE7q3JH2a816zEeyZBXfJi3AKI,42
46
+ pyntcli-0.1.100.dist-info/RECORD,,