insightconnect-plugin-runtime 5.2.4__py3-none-any.whl → 5.3.1__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.
@@ -157,11 +157,13 @@ class Endpoints:
157
157
  500:
158
158
  description: Unexpected error
159
159
  """
160
+ self.logger.info("Plugin task beginning execution...")
160
161
  input_message = request.get_json(force=True)
161
162
  self.logger.debug("Request input: %s", input_message)
162
163
  Endpoints.validate_action_trigger_task_empty_input(input_message)
163
164
  Endpoints.validate_action_trigger_task_name(input_message, name, "task")
164
165
  output = self.run_action_trigger_task(input_message)
166
+ self.logger.info("Plugin task finished execution...")
165
167
  return output
166
168
 
167
169
  @legacy.route("/triggers/<string:name>/test", methods=["POST"])
@@ -1,4 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
+ import structlog
3
+ logger = structlog.get_logger("plugin")
4
+
5
+
2
6
  class ClientException(Exception):
3
7
  """
4
8
  An exception which marks an error made by the plugin invoker.
@@ -120,6 +124,12 @@ class ConnectionTestException(Exception):
120
124
 
121
125
  self.data = str(data) if data else ""
122
126
 
127
+ # Safeguard to ensure the exception is logged across all plugins even if the plugin
128
+ # itself does not call `self.logger.error(<error info>)`
129
+ params = ["cause", "assistance", "data", "preset"]
130
+ info_log = ", ".join([f"{atr}='{getattr(self, atr)}'" for atr in params if getattr(self, atr)])
131
+ logger.error(f"Plugin exception instantiated. {info_log}")
132
+
123
133
  def __str__(self):
124
134
  if self.data:
125
135
  return "Connection test failed!\n\n{cause} {assistance} Response was: {data}".format(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: insightconnect-plugin-runtime
3
- Version: 5.2.4
3
+ Version: 5.3.1
4
4
  Summary: InsightConnect Plugin Runtime
5
5
  Home-page: https://github.com/rapid7/komand-plugin-sdk-python
6
6
  Author: Rapid7 Integrations Alliance
@@ -15,11 +15,11 @@ Description-Content-Type: text/markdown
15
15
  Requires-Dist: requests ==2.31.0
16
16
  Requires-Dist: python-jsonschema-objects ==0.3.12
17
17
  Requires-Dist: jsonschema ==3.2.0
18
- Requires-Dist: certifi ==2022.12.7
18
+ Requires-Dist: certifi ==2023.7.22
19
19
  Requires-Dist: Flask ==2.3.2
20
20
  Requires-Dist: gunicorn ==20.0.4
21
- Requires-Dist: greenlet <=1.1.2,>=0.4.17
22
- Requires-Dist: gevent ==20.9.0
21
+ Requires-Dist: greenlet ==3.0.1
22
+ Requires-Dist: gevent ==23.9.1
23
23
  Requires-Dist: marshmallow ==3.4.0
24
24
  Requires-Dist: apispec ==3.2.0
25
25
  Requires-Dist: apispec-webframeworks ==0.5.2
@@ -48,10 +48,10 @@ to get started.
48
48
 
49
49
  ## Development of the InsightConnect Plugin Runtime
50
50
 
51
- The Python Runtime codebase is built to support Python 3.8+ as of version 4.0.0. The following dependencies will need
51
+ The Python Runtime codebase is built to support Python 3.9.18 as of version 5.3.0. The following dependencies will need
52
52
  to be installed when developing or testing the Plugin Runtime:
53
53
 
54
- - Python 3.8
54
+ - Python 3.9.18
55
55
  - Docker
56
56
  - make
57
57
  - tox
@@ -67,19 +67,51 @@ version and activate it. Then build, install, and confirm the package has been i
67
67
  > source venv/bin/activate
68
68
  > pip install -e ./
69
69
  > pip list | grep insightconnect-plugin-runtime
70
- insightconnect-plugin-runtime 4.0.0
70
+ insightconnect-plugin-runtime 5.2.2
71
71
  ```
72
72
 
73
73
  #### Building the InsightConnect Plugin Runtime Docker Images
74
74
 
75
- Currently the `3-38` dockerfile is used by default when building the docker image. If you want to specify another
76
- dockerfile for testing purposes, such as `3-38-slim`, you can pass it as an argument.
75
+ Currently the `python-3` dockerfile is used by default when building the docker image. If you want to specify another
76
+ dockerfile for testing purposes, such as `python-3-slim`, you can pass it as an argument.
77
77
 
78
78
  ```
79
- make build-image DOCKERFILE=3-38-slim
79
+ make build-image DOCKERFILE=python-3-slim
80
80
  ```
81
81
 
82
- This will overwrite the default `3-38`, provided that it exists in the `dockerfiles` directory.
82
+ This will overwrite the default `python-3`, provided that it exists in the `dockerfiles` directory.
83
+
84
+ #### Building/troubleshooting local images (Mac M1)
85
+
86
+ Our images are built with OS/ARCH:linux/amd64 due to our ci.yml file specifying linux. Historically this has
87
+ not caused any issues but with an M1 Mac, docker will now use arm64. This is because docker builds the image to match the
88
+ distribution of the OS running the command. To ensure that building locally and on GH produces an image of the same
89
+ architecture the `--platform` specifier is passed in the dockerfile.
90
+
91
+ If you build a plugin locally we can see further issues that:
92
+ - the local image does match the current OS distro so docker continues to look remotely..
93
+ - docker can not find this (newly created) image remotely on docker registry (dev images should not be pushed to registry)
94
+
95
+ To overcome this we need to specify `platform=linux/amd64` in the plugin docker file. E.g. if building plugins/html then
96
+ this file should be updated `plugins/html/Dockerfile`.
97
+ *Note*: building this arch on mac M1 will cause the build to be slower.
98
+
99
+
100
+ Example error of local image not matching OS distro without passing the `--platform` flag:
101
+ ```
102
+ => ERROR [internal] load metadata for docker.io/rapid7/insightconnect-python-3-slim-plugin:latest 1.4s
103
+ ------
104
+ > [internal] load metadata for docker.io/rapid7/insightconnect-python-3-slim-plugin:latest:
105
+ ------
106
+ Dockerfile:1
107
+ --------------------
108
+ 1 | >>> FROM rapid7/insightconnect-python-3-slim-plugin
109
+ 2 | LABEL organization=rapid7
110
+ 3 | LABEL sdk=python
111
+ --------------------
112
+ ERROR: failed to solve: rapid7/insightconnect-python-3-slim-plugin: pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
113
+ make: *** [image] Error 1
114
+ ```
83
115
 
84
116
  ### Testing Sample Plugin
85
117
  The easiest way to test changes to the runtime is by running it locally against one of the [sample plugins](./samples)
@@ -145,9 +177,21 @@ Running all tests:
145
177
 
146
178
  Running a specific test file:
147
179
  ```
148
- > tox -e py38 -- tests/plugin/hello_world/tests/test_cli.py
180
+ > tox -e py39 -- tests/plugin/hello_world/tests/test_cli.py
149
181
  ```
150
182
 
183
+ ## Plugin vs Slim Plugin Comparison
184
+
185
+ | | Plugin | Slim Plugin |
186
+ |:------------------|:-------:|:-----------:|
187
+ | Python Version | 3.9.18 | 3.9.18 |
188
+ | OS | Alpine | Bullseye |
189
+ | Package installer | apk | apt |
190
+ | Shell | /bin/sh | /bin/bash |
191
+ | Image Size | ~350MB | ~180MB |
192
+
193
+ Note that for the plugin image, we run `apk update` and `apk add ..` which leads to a longer build time.
194
+
151
195
  ## Release
152
196
 
153
197
  To release a new version of the InsightConnect Python Plugin Runtime, the below steps must be followed:
@@ -168,6 +212,8 @@ after cloning this repository.
168
212
 
169
213
  ## Changelog
170
214
 
215
+ * 5.3.1 - New logging added to the beginning and end of a task | New logging when an exception is instantiated.
216
+ * 5.3.0 - Update base images to pull Python 3.9.18 | python packages bump | rename image to drop python minor version.
171
217
  * 5.2.4 - Extended logging with OrgID and IntID
172
218
  * 5.2.3 - Extended logging in AWSClient
173
219
  * 5.2.2 - Fix longstanding bug where some error responses from a plugin could be in HTML format instead of JSON
@@ -3,7 +3,7 @@ insightconnect_plugin_runtime/action.py,sha256=8gsOONf7mzY83O3DNjCBIafk7C7acnf7m
3
3
  insightconnect_plugin_runtime/cli.py,sha256=Pb-Janu-XfRlSXxPHh30OIquljWptrhhS51C3clJqh4,8939
4
4
  insightconnect_plugin_runtime/connection.py,sha256=4bHHV2B0UFGsAtvLu1fiYQRwx7fissUakHPUyjLQO0E,2340
5
5
  insightconnect_plugin_runtime/dispatcher.py,sha256=ru7njnyyWE1-oD-VbZJ-Z8tELwvDf69rM7Iezs4rbnw,1774
6
- insightconnect_plugin_runtime/exceptions.py,sha256=YEbm63_s6J6978Elsfz2mavoSaxdtPVkHPC6WYNDTBI,6060
6
+ insightconnect_plugin_runtime/exceptions.py,sha256=rC74M9aCSrY7J-nq9ttsccLkNbHR0gbZ2SRvXlCgLx0,6507
7
7
  insightconnect_plugin_runtime/helper.py,sha256=m5PxN04-NPXM1X10S2wwjqmiLvnNntd6TnwLoW4nnus,21108
8
8
  insightconnect_plugin_runtime/metrics.py,sha256=hf_Aoufip_s4k4o8Gtzz90ymZthkaT2e5sXh5B4LcF0,3186
9
9
  insightconnect_plugin_runtime/plugin.py,sha256=YEwxPHyIYsQcGAZYQZqh60POQOzbrtsZAcA5TcBmy8g,22708
@@ -15,7 +15,7 @@ insightconnect_plugin_runtime/trigger.py,sha256=Zq3cy68N3QxAGbNZKCID6CZF05Zi7YD2
15
15
  insightconnect_plugin_runtime/util.py,sha256=lE6UVOYyzY9Ldyqpf91V24CvvdKjUu3WjGOSy957Sm0,8073
16
16
  insightconnect_plugin_runtime/variables.py,sha256=7FjJGnU7KUR7m9o-_tRq7Q3KiaB1Pp0Apj1NGgOwrJk,3056
17
17
  insightconnect_plugin_runtime/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- insightconnect_plugin_runtime/api/endpoints.py,sha256=BjLr9YNM9J5cHXWfpD49JvBSB93jr-EChXxmXHhFVig,28966
18
+ insightconnect_plugin_runtime/api/endpoints.py,sha256=jjKTFArNIOJkZw-L0QU_1yzRcKC6xyAC8ge86M6fQjQ,29099
19
19
  insightconnect_plugin_runtime/api/schemas.py,sha256=jRmDrwLJTBl-iQOnyZkSwyJlCWg4eNjAnKfD9Eko4z0,2754
20
20
  insightconnect_plugin_runtime/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  insightconnect_plugin_runtime/clients/aws_client.py,sha256=3Ytx-uchkl7dTcwYKZPKvCJaWralEqZUZeireOCWlPo,20290
@@ -23,7 +23,7 @@ insightconnect_plugin_runtime/clients/oauth.py,sha256=bWtAGRMwdK4dw9vMPcw9usklyI
23
23
  insightconnect_plugin_runtime/data/input_message_schema.json,sha256=7_BcHi6UOBiVWGrrJHHn5IoddteXjL7GOKETdO9T2DE,1770
24
24
  insightconnect_plugin_runtime/data/output_message_schema.json,sha256=Qya6U-NR5MfOlw4V98VpQzGBVq75eGMUQhI-j3yxOHI,1137
25
25
  tests/__init__.py,sha256=uKG3ssG-d51oNHQxKheE9Wzcusd7OW3ei6EYT3WxPnw,106
26
- tests/plugin/__init__.py,sha256=oZCsCJtYxak9TF8ATlV2ee5JklIJr87WITkvC69GTqM,2430
26
+ tests/plugin/__init__.py,sha256=ZTPmMxZoDAHcbFqyIQVFkeifTfun5f5r_hffPP17Y2w,2713
27
27
  tests/plugin/hello_world/__init__.py,sha256=fzr7Uek0yDCKBchW3fgtv1IAp8JIlW335GwENk4-wPk,42
28
28
  tests/plugin/hello_world/hello_world/__init__.py,sha256=rJm2tr4rZ2uR9AfjMyoQRntFM0JOf2SpHCfO7uWho2g,1018
29
29
  tests/plugin/hello_world/hello_world/setup.py,sha256=-NAHjSoYB-qU4fZrs_0nHzN7OxkSJ7OHUvQE8SXA6eg,467
@@ -44,13 +44,13 @@ tests/plugin/hello_world/hello_world/komand_hello_world/connection/schema.py,sha
44
44
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/__init__.py,sha256=6gwJkxwZLglGm_nIhMo96z5uM2ENAIHYxpJneuEDRrU,221
45
45
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/hello_trigger/__init__.py,sha256=b8c55qKjWULUk5uhTvzSs246lm8VQxw0h4nvTyYqWuA,74
46
46
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/hello_trigger/schema.py,sha256=NGOXa58BprKTZjyF4BNGPPnRnGnAqwVnZYNiIWElDZg,944
47
- tests/plugin/hello_world/hello_world/komand_hello_world/triggers/hello_trigger/trigger.py,sha256=P4f95CO_45zn2Bx5AuhPu_xca1Az9w-3x6FHO9gXe74,793
47
+ tests/plugin/hello_world/hello_world/komand_hello_world/triggers/hello_trigger/trigger.py,sha256=PYPY8aW1h6mvQf61sE3ngopXm5SCOeRyhSm7-I1-Hr0,1148
48
48
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/return_bad_json_trigger/__init__.py,sha256=PxfCcfOn24CwtojXbyI8qYTGhfv49kZMR5P30UdJhdg,82
49
49
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/return_bad_json_trigger/schema.py,sha256=7M5gAmMzj_DWSZ982yu-J8yL6mjlCPld1nmNkx30_UE,960
50
50
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/return_bad_json_trigger/trigger.py,sha256=1amZOxQiWaSdUwGjN-siTVSZw71ouUX4Xlp73Gh17yc,717
51
51
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/throw_exception_trigger/__init__.py,sha256=gwdLBOIougxWEhHEQkOueHlWv0Ocq0EjzlfqwcfLucA,83
52
52
  tests/plugin/hello_world/hello_world/komand_hello_world/triggers/throw_exception_trigger/schema.py,sha256=Y1FozH6fhm8apf_5yncc3mDT51Xqw_c-JzgB_x1sssU,962
53
- tests/plugin/hello_world/hello_world/komand_hello_world/triggers/throw_exception_trigger/trigger.py,sha256=BRBm3h6L2WGObYqb9W7P16DTrgFvPHl067w19OsXRwU,680
53
+ tests/plugin/hello_world/hello_world/komand_hello_world/triggers/throw_exception_trigger/trigger.py,sha256=pydbyz09YdLzq_NrdvNW11Fhr53INn1NWa4TZ7L9DUw,696
54
54
  tests/plugin/hello_world/hello_world/komand_hello_world/util/__init__.py,sha256=RAUlyeHr0LBBRVgwatrSBl7iAaUmrw8Z6BAZlCby_vY,40
55
55
  tests/plugin/hello_world/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
56
  tests/plugin/hello_world/tests/conftest.py,sha256=fM3XJmVDHMeYZA__yjXVocgx7kwgr5FRwcWsY1XsV70,1046
@@ -71,7 +71,7 @@ tests/unit/test_schema.py,sha256=swWZPRo_Q4M6VHte-srmxcV2wH-XS7pgmNRxpaL0Qrg,642
71
71
  tests/unit/test_server_spec.py,sha256=7hmXdsY36nP0ENhijrolBInAMJwht2-Z-D6yhcg_zZI,578
72
72
  tests/unit/test_trigger.py,sha256=E53mAUoVyponWu_4IQZ0IC1gQ9lakBnTn_9vKN2IZfg,1692
73
73
  tests/unit/test_variables.py,sha256=OUEOqGYZA3Nd5oKk5GVY3hcrWKHpZpxysBJcO_v5gzs,291
74
- insightconnect_plugin_runtime-5.2.4.dist-info/METADATA,sha256=DDsZqrWzHfulFn90APOnV1Ng09hsyjGKkk1Uo-ceqZE,9579
75
- insightconnect_plugin_runtime-5.2.4.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
76
- insightconnect_plugin_runtime-5.2.4.dist-info/top_level.txt,sha256=AJtyJOpiFzHxsbHUICTcUKXyrGQ3tZxhrEHsPjJBvEA,36
77
- insightconnect_plugin_runtime-5.2.4.dist-info/RECORD,,
74
+ insightconnect_plugin_runtime-5.3.1.dist-info/METADATA,sha256=nNNrHZvzCIPzoz3isVDx8T05UKQckWjbQOzz6Wp03mY,12026
75
+ insightconnect_plugin_runtime-5.3.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
76
+ insightconnect_plugin_runtime-5.3.1.dist-info/top_level.txt,sha256=AJtyJOpiFzHxsbHUICTcUKXyrGQ3tZxhrEHsPjJBvEA,36
77
+ insightconnect_plugin_runtime-5.3.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.3)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
tests/plugin/__init__.py CHANGED
@@ -55,10 +55,16 @@ def run_trigger(input_file, output_file, plugin, expect_timeout=False):
55
55
  plugin.triggers[trigger_name].dispatcher = capture
56
56
 
57
57
  executor = thread.ThreadPoolExecutor()
58
- executor.submit(plugin.handle_step, input_message)
59
- future = executor.submit(capture.wait_for_caught_message)
60
- out = futures.wait([future], timeout=10)
61
- done = out.done
58
+
59
+ if expect_timeout:
60
+ future = executor.submit(plugin.handle_step, input_message)
61
+ future_ans = future.exception()
62
+ done = future_ans.output
63
+ else:
64
+ executor.submit(plugin.handle_step, input_message)
65
+ future = executor.submit(capture.wait_for_caught_message)
66
+ out = futures.wait([future], timeout=10)
67
+ done = out.done
62
68
 
63
69
  # Non-graceful shutdown
64
70
  executor._threads.clear()
@@ -69,7 +75,8 @@ def run_trigger(input_file, output_file, plugin, expect_timeout=False):
69
75
  return
70
76
  raise Exception("Timeout")
71
77
 
72
- output = capture.caught_message
78
+ # output = capture.caught_message
79
+ output = done if expect_timeout else capture.caught_message
73
80
 
74
81
  if "body" in output and "log" in output["body"]:
75
82
  output["body"]["log"] = ""
@@ -79,7 +86,7 @@ def run_trigger(input_file, output_file, plugin, expect_timeout=False):
79
86
 
80
87
  if output != expected_output:
81
88
  raise Exception(
82
- "Actual output differs from expected output.{} != {}".format(
83
- output, expected_output
84
- )
89
+ f"Actual output differs from expected output/ \n"
90
+ f"Actual output: {output} \n"
91
+ f"Expected output: {expected_output}"
85
92
  )
@@ -18,8 +18,14 @@ class HelloTrigger(insightconnect_plugin_runtime.Trigger):
18
18
  """Run the trigger"""
19
19
  while True:
20
20
  self.logger.info("I am the log")
21
- self.send({"message": self.connection.greeting.format(params["name"])})
21
+ resp = {"message": self.connection.greeting.format(params["name"])}
22
+ self.send(resp)
22
23
  time.sleep(10)
24
+ # because this is a test we need to return otherwise the thread runs indefinitely to match how
25
+ # triggers run in production. Check using params 'test' so that if we build image of this plugin and
26
+ # test we will enter the loop as usual.
27
+ if params["test"]:
28
+ return resp
23
29
 
24
30
  def test(self):
25
31
  self.logger.info("This is a test")
@@ -15,7 +15,7 @@ class ThrowExceptionTrigger(insightconnect_plugin_runtime.Trigger):
15
15
  )
16
16
 
17
17
  def run(self, params={}):
18
- raise Exception("because I can")
18
+ raise Exception("Forced exception test")
19
19
 
20
20
  def test(self, params={}):
21
- raise Exception("because I can")
21
+ raise Exception("Forced exception test")