pyntcli 0.1.99__py3-none-any.whl → 0.1.101__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.101"
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=port, dest=PYNT_CONTAINER_INTERNAL_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=port, dest=PYNT_CONTAINER_INTERNAL_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(args.port, PYNT_CONTAINER_INTERNAL_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,9 +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
- from docker.types import Mount
7
3
  import os
8
4
  import json
9
5
  import argparse
@@ -24,7 +20,13 @@ PYNT_CONTAINER_INTERNAL_PORT = "5001"
24
20
 
25
21
 
26
22
  def create_mount(src, destination, mount_type="bind"):
27
- return Mount(target=destination, source=src, type=mount_type)
23
+ return {
24
+ 'Target': destination,
25
+ 'Source': src,
26
+ 'Type': mount_type,
27
+ 'ReadOnly': False,
28
+ 'NoCopy': False,
29
+ }
28
30
 
29
31
 
30
32
  class DockerNotAvailableException(Exception):
@@ -46,7 +48,7 @@ class PortInUseException(Exception):
46
48
  super().__init__(self.message)
47
49
 
48
50
 
49
- def get_docker_platform_by_native_command():
51
+ def get_docker_platform_name():
50
52
  try:
51
53
  version_data = json.loads(subprocess.check_output(["docker", "version", "--format", "{{json .}}"], text=True))
52
54
  platform = version_data.get("Server", {}).get("Platform", {})
@@ -56,23 +58,6 @@ def get_docker_platform_by_native_command():
56
58
  raise DockerNotAvailableException()
57
59
 
58
60
 
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
61
  class PyntBaseContainer():
77
62
  def __init__(self, docker_type, docker_arguments, mounts, environment={}) -> None:
78
63
  self.docker_type = docker_type
@@ -88,33 +73,83 @@ class PyntDockerPort:
88
73
  self.name = name
89
74
 
90
75
 
91
- def is_network_host(use_docker_sdk: bool) -> bool:
76
+ class PyntDockerImage:
77
+ def __init__(self, name, is_self_managed) -> None:
78
+ self.name = name
79
+ self.is_self_managed = is_self_managed
80
+
81
+
82
+ class DockerContainerConfig:
83
+ def __init__(self, args: argparse.Namespace, integration_name: str, *port_args: PyntDockerPort):
84
+ self.image = get_image_config(args)
85
+ self.is_detach = True
86
+ self.ports = port_args
87
+ self.docker_arguments = build_docker_args(integration_name, args)
88
+ self.mounts = get_docker_mounts(args)
89
+ self.env_vars = {PYNT_ID: CredStore().get_tokens(), "PYNT_SAAS_URL": PYNT_SAAS}
90
+ if user_set_all_variables():
91
+ add_env_variables(self.env_vars)
92
+
93
+ ports = {}
94
+ create_network_host = is_network_host()
95
+ for p in port_args:
96
+ if create_network_host:
97
+ self.docker_arguments.append(p.name)
98
+ self.docker_arguments.append(str(p.dest))
99
+ else:
100
+ ports[str(p.src)] = int(p.dest)
101
+
102
+ if create_network_host:
103
+ self.docker_type = PyntNativeHost(network="host")
104
+ else:
105
+ self.docker_type = PyntDockerDesktopContainer(ports=ports)
106
+
107
+
108
+ def get_image_config(args: argparse.Namespace) -> PyntDockerImage:
109
+ default_image = f'{PYNT_DOCKER_IMAGE}:v1-latest'
110
+ if "pynt_image" in args and args.pynt_image:
111
+ return PyntDockerImage(args.pynt_image, True)
112
+ env_name = value_from_environment_variable("IMAGE")
113
+ env_tag = value_from_environment_variable("TAG")
114
+ if env_name:
115
+ return PyntDockerImage(f'{env_name}:{env_tag}', True)
116
+
117
+ return PyntDockerImage(default_image, False)
118
+
119
+
120
+ def is_network_host() -> bool:
92
121
  platform_sys_name = platform.system()
93
122
  if platform_sys_name == "Windows" or platform_sys_name == "Darwin":
94
123
  return False
95
124
  else:
96
- docker_platform_name = get_docker_platform_by_sdk().lower() if use_docker_sdk else get_docker_platform_by_native_command().lower()
125
+ docker_platform_name = get_docker_platform_name().lower()
97
126
  if "desktop" in docker_platform_name:
98
127
  return False
99
128
  return True
100
129
 
101
130
 
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)
131
+ def user_set_all_variables():
132
+ return all([PYNT_BUCKET_NAME, PYNT_PARAM1, PYNT_PARAM2])
113
133
 
114
- if create_network_host:
115
- docker_type = PyntNativeContainer(network="host")
116
- else:
117
- docker_type = PyntDockerDesktopContainer(ports=ports)
134
+
135
+ def add_env_variables(env: dict):
136
+ env["PYNT_BUCKET_NAME"] = PYNT_BUCKET_NAME
137
+ env["PYNT_PARAM1"] = base64.b64encode(PYNT_PARAM1.encode('utf-8'))
138
+ env["PYNT_PARAM2"] = base64.b64encode(PYNT_PARAM2.encode('utf-8'))
139
+
140
+
141
+ def value_from_environment_variable(key):
142
+ e = os.environ.get(key)
143
+
144
+ if e:
145
+ ui_thread.print_verbose(f"Using environment variable {key}={e}")
146
+ return e
147
+
148
+ return None
149
+
150
+
151
+ def build_docker_args(integration_name:str, args: argparse.Namespace) -> list[str]:
152
+ docker_arguments = [integration_name]
118
153
 
119
154
  if "insecure" in args and args.insecure:
120
155
  docker_arguments.append("--insecure")
@@ -128,73 +163,46 @@ def get_container_with_arguments(integration: str, args: argparse.Namespace, *po
128
163
  if "dev_flags" in args:
129
164
  docker_arguments += args.dev_flags.split(" ")
130
165
 
131
- mounts = []
132
166
  if "host_ca" in args and args.host_ca:
133
167
  ca_name = os.path.basename(args.host_ca)
134
168
  docker_arguments += ["--host-ca", ca_name]
135
- mounts.append(create_mount(os.path.abspath(args.host_ca), "/etc/pynt/{}".format(ca_name)))
136
169
 
137
170
  if "transport_config" in args and args.transport_config:
138
171
  tc_name = os.path.basename(args.transport_config)
139
172
  docker_arguments += ["--transport-config", tc_name]
140
- mounts.append(create_mount(os.path.abspath(args.transport_config), "/etc/pynt/{}".format(tc_name)))
141
173
 
142
174
  if "verbose" in args and args.verbose:
143
175
  docker_arguments.append("--verbose")
144
176
 
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
-
177
+ return docker_arguments
155
178
 
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
179
 
180
+ def get_docker_mounts(args: argparse.Namespace) -> list:
181
+ mounts = []
182
+ if "host_ca" in args and args.host_ca:
183
+ ca_name = os.path.basename(args.host_ca)
184
+ mounts.append(create_mount(os.path.abspath(args.host_ca), "/etc/pynt/{}".format(ca_name)))
172
185
 
173
- def value_from_environment_variable(key, fallback=""):
174
- e = os.environ.get(key)
186
+ if "transport_config" in args and args.transport_config:
187
+ tc_name = os.path.basename(args.transport_config)
188
+ mounts.append(create_mount(os.path.abspath(args.transport_config), "/etc/pynt/{}".format(tc_name)))
175
189
 
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
190
+ return mounts
182
191
 
183
192
 
184
193
  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
192
- self.container_name = ""
194
+ def __init__(self, container_config: DockerContainerConfig):
195
+ self.config = container_config
196
+ self.container_name = "pynt_engine"
193
197
  self.system = platform.system().lower()
194
-
195
198
  self.stdout = None
196
199
  self.running = False
197
200
 
201
+ creds_path = os.path.dirname(CredStore().file_location)
202
+ mitm_cert_path = os.path.join(creds_path, "cert")
203
+ os.makedirs(mitm_cert_path, exist_ok=True)
204
+ self.config.mounts.append(create_mount(mitm_cert_path, "/root/.mitmproxy"))
205
+
198
206
  def is_alive(self):
199
207
  command = ["docker", "ps", "--filter", f"name={self.container_name}", "--filter", "status=running"]
200
208
  result = subprocess.run(
@@ -211,23 +219,20 @@ class PyntContainerNative:
211
219
  def run(self):
212
220
  self.running = True
213
221
 
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")
222
+ self.fetch_and_validate_image()
223
+ args = self.config.docker_arguments if self.config.docker_arguments else None
224
+ docker_command = ["docker", "run", "--rm", "-d", "--name", self.container_name]
220
225
 
221
226
  mounts = []
222
- for mount in self.base_container.mounts:
227
+ for mount in self.config.mounts:
223
228
  mounts.extend(["-v", f"{mount['Source']}:{mount['Target']}"])
224
229
 
225
230
  env_vars = []
226
- for key, value in self.base_container.environment.items():
231
+ for key, value in self.config.env_vars.items():
227
232
  env_vars.extend(self.adapt_environment_variable_partial(key, value))
228
233
 
229
234
  docker_type_options = []
230
- for key, value in self.base_container.docker_type.get_arguments().items():
235
+ for key, value in self.config.docker_type.get_arguments().items():
231
236
  if key == "ports":
232
237
  if isinstance(value, dict):
233
238
  for s, d in value.items():
@@ -239,10 +244,11 @@ class PyntContainerNative:
239
244
  docker_command += mounts
240
245
  docker_command += env_vars
241
246
  docker_command += docker_type_options
242
- docker_command += [f"{self.image_name}:{self.tag}"]
247
+ docker_command += [f"{self.config.image.name}"]
243
248
  docker_command += args
244
249
 
245
250
  command = self.adapt_run_command(docker_command)
251
+ PyntContainerRegistry.instance().register_container(self)
246
252
  process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
247
253
  stdout, stderr = process.communicate()
248
254
 
@@ -268,8 +274,8 @@ class PyntContainerNative:
268
274
  def kill_other_instances(self, report_to_user=True):
269
275
  ui_thread.print_verbose("Killing other pynt containers if such exist")
270
276
  try:
271
- for tag in IMAGE_TAGS:
272
- command = ["docker", "ps", "-q", "-f", f"ancestor={self.image_name}:{tag}"]
277
+ for _ in IMAGE_TAGS:
278
+ command = ["docker", "ps", "-q", "-f", f"name={self.container_name}"]
273
279
  containers_output = subprocess.check_output(command, text=True)
274
280
  if not containers_output:
275
281
  continue
@@ -286,41 +292,28 @@ class PyntContainerNative:
286
292
  analytics.emit(analytics.ERROR, {"error": "Unable to kill other pynt containers"})
287
293
  ui_thread.print(ui_thread.PrinterText("Error: Unable to kill other pynt containers", ui_thread.PrinterText.WARNING))
288
294
 
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):
295
+ def fetch_and_validate_image(self):
299
296
  try:
300
297
  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))
298
+ pull_command = ['docker', 'pull', self.config.image.name]
299
+ get_image_command = ['docker', 'images', '-q', f'{self.config.image.name}']
300
+ pull_process = subprocess.Popen(pull_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
301
+ _, pull_stderr = pull_process.communicate()
302
+ get_process = subprocess.Popen(get_image_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
303
+ get_stdout, _ = get_process.communicate()
304
+ local_image_id = get_stdout.decode('utf-8')
305
+ if self.config.image.is_self_managed and local_image_id:
306
+ return local_image_id.strip()
307
+ elif local_image_id == "":
308
+ ui_thread.print(ui_thread.PrinterText(f"Error: the image {self.config.image.name} not found",
309
+ ui_thread.PrinterText.WARNING))
310
+ raise ImageUnavailableException("Failed to find local image")
311
+ if pull_stderr and local_image_id == "":
312
+ ui_thread.print(ui_thread.PrinterText(f"Error: {pull_stderr}", ui_thread.PrinterText.WARNING))
317
313
  raise ImageUnavailableException("Failed to pull image")
318
314
 
319
- if process.returncode != 0:
315
+ if pull_process.returncode != 0:
320
316
  raise ImageUnavailableException("Failed to pull image")
321
-
322
- image_id = stdout.strip()
323
- return image_id
324
317
  except Exception as e:
325
318
  raise ImageUnavailableException(f"An error occurred: {str(e)}")
326
319
 
@@ -340,169 +333,12 @@ class PyntContainerNative:
340
333
  return ["-e", f"{key}={json.dumps(value)}"]
341
334
  return ["-e", f"{key}={value}"]
342
335
 
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
336
  def pre_run_validation(self, port):
495
337
  self.kill_other_instances()
496
338
 
497
339
  if container_utils.is_port_in_use(int(port)):
498
340
  raise PortInUseException(port)
499
341
 
500
- def prepare_client(self):
501
- self.client_implementation.prepare_client()
502
-
503
- def running(self):
504
- return self.client_implementation.running
505
-
506
342
 
507
343
  class PyntDockerDesktopContainer:
508
344
  def __init__(self, ports) -> None:
@@ -512,7 +348,7 @@ class PyntDockerDesktopContainer:
512
348
  return {"ports": self.ports} if self.ports else {}
513
349
 
514
350
 
515
- class PyntNativeContainer:
351
+ class PyntNativeHost:
516
352
  def __init__(self, network) -> None:
517
353
  self.network = network
518
354
 
@@ -524,7 +360,7 @@ class PyntContainerRegistry:
524
360
  _instance = None
525
361
 
526
362
  def __init__(self) -> None:
527
- self.containers: List[PyntContainer] = []
363
+ self.containers: List[PyntContainerNative] = []
528
364
 
529
365
  @staticmethod
530
366
  def instance():
@@ -533,7 +369,7 @@ class PyntContainerRegistry:
533
369
 
534
370
  return PyntContainerRegistry._instance
535
371
 
536
- def register_container(self, c: PyntContainer):
372
+ def register_container(self, c: PyntContainerNative):
537
373
  self.containers.append(c)
538
374
 
539
375
  def stop_all_containers(self):
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyntcli
3
- Version: 0.1.99
3
+ Version: 0.1.101
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
7
7
  Requires-Python: >=3.7
8
- Requires-Dist: docker
9
8
  Requires-Dist: rich
10
9
  Requires-Dist: requests==2.31.0
11
10
  Requires-Dist: pem
@@ -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=QzGQWEX3yxu6r8-t7XWvYoCSv5J8shJ6psVFM2wOqZ8,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=NJ_xnx6ONwHXWEr1PQ8julW3IHfBFtifSAIzHtVGyKg,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=MuY_y0-UGMATXbe2rAHVzq40TfQWLecN9_F2ulvZolw,5173
17
+ pyntcli/commands/postman.py,sha256=u7LFpsxs8kcraZMY_iDAfNPOCfg1ZrfQlXURbW1dCYg,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=RoRn_prg-0xcg3H8aRV5psUsmYoM6j-4Ri7DonPFjVM,13215
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.101.dist-info/METADATA,sha256=xU3ZbcTk4XwPMDcuJcy7Io715m1xc4soqJEImm7loTQ,472
43
+ pyntcli-0.1.101.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
44
+ pyntcli-0.1.101.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
45
+ pyntcli-0.1.101.dist-info/top_level.txt,sha256=64XSgBzSpgwjYjEKHZE7q3JH2a816zEeyZBXfJi3AKI,42
46
+ pyntcli-0.1.101.dist-info/RECORD,,