insightconnect-plugin-runtime 6.3.4__tar.gz → 6.3.6__tar.gz
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.
- {insightconnect_plugin_runtime-6.3.4/insightconnect_plugin_runtime.egg-info → insightconnect_plugin_runtime-6.3.6}/PKG-INFO +13 -10
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/README.md +2 -0
- insightconnect_plugin_runtime-6.3.6/insightconnect_plugin_runtime/telemetry.py +193 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/util.py +43 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6/insightconnect_plugin_runtime.egg-info}/PKG-INFO +13 -10
- insightconnect_plugin_runtime-6.3.6/insightconnect_plugin_runtime.egg-info/requires.txt +20 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/setup.py +11 -10
- insightconnect_plugin_runtime-6.3.4/insightconnect_plugin_runtime/telemetry.py +0 -94
- insightconnect_plugin_runtime-6.3.4/insightconnect_plugin_runtime.egg-info/requires.txt +0 -19
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/MANIFEST.in +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect-plugin-swagger.json +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/action.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/api/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/api/endpoints.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/api/schemas.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/cli.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/clients/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/clients/aws_client.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/clients/oauth.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/connection.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/data/input_message_schema.json +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/data/output_message_schema.json +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/dispatcher.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/exceptions.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/helper.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/metrics.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/plugin.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/server.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/step.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/task.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/trigger.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime/variables.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime.egg-info/SOURCES.txt +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime.egg-info/dependency_links.txt +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/insightconnect_plugin_runtime.egg-info/top_level.txt +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/setup.cfg +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/hello/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/hello/action.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/hello/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/return_bad_json/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/return_bad_json/action.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/return_bad_json/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/throw_exception/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/throw_exception/action.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/actions/throw_exception/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/connection/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/connection/connection.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/connection/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/tasks/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/tasks/monitor_events/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/tasks/monitor_events/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/tasks/monitor_events/task.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/hello_trigger/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/hello_trigger/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/hello_trigger/trigger.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/return_bad_json_trigger/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/return_bad_json_trigger/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/return_bad_json_trigger/trigger.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/throw_exception_trigger/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/throw_exception_trigger/schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/triggers/throw_exception_trigger/trigger.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/komand_hello_world/util/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/hello_world/setup.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/tests/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/tests/conftest.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/tests/test_cli.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/tests/test_hello_world.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/hello_world/tests/test_server.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/__init__.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_action.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_api.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_aws_action.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_custom_encoder.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_endpoints.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_exceptions.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_helpers.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_metrics.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_oauth.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_plugin.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_schema.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_server_cloud_plugins.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_server_spec.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_trigger.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_variables.py +0 -0
- {insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: insightconnect-plugin-runtime
|
|
3
|
-
Version: 6.3.
|
|
3
|
+
Version: 6.3.6
|
|
4
4
|
Summary: InsightConnect Plugin Runtime
|
|
5
5
|
Home-page: https://github.com/rapid7/komand-plugin-sdk-python
|
|
6
6
|
Author: Rapid7 Integrations Alliance
|
|
@@ -12,25 +12,26 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
12
12
|
Classifier: Natural Language :: English
|
|
13
13
|
Classifier: Topic :: Software Development :: Build Tools
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
-
Requires-Dist: requests==2.32.
|
|
15
|
+
Requires-Dist: requests==2.32.4
|
|
16
16
|
Requires-Dist: python_jsonschema_objects==0.5.2
|
|
17
17
|
Requires-Dist: jsonschema==4.22.0
|
|
18
|
-
Requires-Dist: certifi==
|
|
18
|
+
Requires-Dist: certifi==2025.4.26
|
|
19
19
|
Requires-Dist: Flask==3.1.1
|
|
20
20
|
Requires-Dist: gunicorn==23.0.0
|
|
21
|
-
Requires-Dist: greenlet==3.
|
|
22
|
-
Requires-Dist: gevent==
|
|
21
|
+
Requires-Dist: greenlet==3.2.3
|
|
22
|
+
Requires-Dist: gevent==25.5.1
|
|
23
23
|
Requires-Dist: marshmallow==3.21.0
|
|
24
24
|
Requires-Dist: apispec==6.5.0
|
|
25
25
|
Requires-Dist: apispec-webframeworks==1.0.0
|
|
26
26
|
Requires-Dist: blinker==1.9.0
|
|
27
|
-
Requires-Dist: structlog==
|
|
27
|
+
Requires-Dist: structlog==25.4.0
|
|
28
28
|
Requires-Dist: python-json-logger==2.0.7
|
|
29
29
|
Requires-Dist: Jinja2==3.1.6
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-Dist: opentelemetry-
|
|
32
|
-
Requires-Dist: opentelemetry-
|
|
33
|
-
Requires-Dist: opentelemetry-
|
|
30
|
+
Requires-Dist: python-dateutil==2.9.0.post0
|
|
31
|
+
Requires-Dist: opentelemetry-sdk==1.34.0
|
|
32
|
+
Requires-Dist: opentelemetry-instrumentation-flask==0.55b0
|
|
33
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.34.0
|
|
34
|
+
Requires-Dist: opentelemetry-instrumentation-requests==0.55b0
|
|
34
35
|
Dynamic: author
|
|
35
36
|
Dynamic: author-email
|
|
36
37
|
Dynamic: classifier
|
|
@@ -224,6 +225,8 @@ contributed. Black is installed as a test dependency and the hook can be initial
|
|
|
224
225
|
after cloning this repository.
|
|
225
226
|
|
|
226
227
|
## Changelog
|
|
228
|
+
* 6.3.6 - Added required dependency to plugin runtime
|
|
229
|
+
* 6.3.5 - Added `monitor_task_delay` decorator to detect processing delays
|
|
227
230
|
* 6.3.4 - Addressed vulnerabilities within the slim and non-slim Python images (bumping packages)
|
|
228
231
|
* 6.3.3 - Add helper func for tracing context to preserve parent span in threadpools
|
|
229
232
|
* 6.3.2 - Raise `APIException` from within the `response_handler` to easily access the status code within the plugin
|
|
@@ -182,6 +182,8 @@ contributed. Black is installed as a test dependency and the hook can be initial
|
|
|
182
182
|
after cloning this repository.
|
|
183
183
|
|
|
184
184
|
## Changelog
|
|
185
|
+
* 6.3.6 - Added required dependency to plugin runtime
|
|
186
|
+
* 6.3.5 - Added `monitor_task_delay` decorator to detect processing delays
|
|
185
187
|
* 6.3.4 - Addressed vulnerabilities within the slim and non-slim Python images (bumping packages)
|
|
186
188
|
* 6.3.3 - Add helper func for tracing context to preserve parent span in threadpools
|
|
187
189
|
* 6.3.2 - Raise `APIException` from within the `response_handler` to easily access the status code within the plugin
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import contextvars
|
|
2
|
+
from datetime import UTC, datetime
|
|
3
|
+
from functools import partial, wraps
|
|
4
|
+
from typing import Any, Callable, List, Union
|
|
5
|
+
|
|
6
|
+
from dateutil.parser import parse
|
|
7
|
+
from flask.app import Flask
|
|
8
|
+
from opentelemetry import trace
|
|
9
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
10
|
+
from opentelemetry.instrumentation.flask import FlaskInstrumentor
|
|
11
|
+
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
|
12
|
+
from opentelemetry.sdk.resources import Resource
|
|
13
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
14
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
15
|
+
from opentelemetry.trace import Status, StatusCode
|
|
16
|
+
|
|
17
|
+
from insightconnect_plugin_runtime.plugin import Plugin
|
|
18
|
+
from insightconnect_plugin_runtime.util import (
|
|
19
|
+
OTEL_ENDPOINT,
|
|
20
|
+
is_running_in_cloud,
|
|
21
|
+
parse_from_string,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def init_tracing(app: Flask, plugin: Plugin, endpoint: str) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Initialize OpenTelemetry Tracing
|
|
28
|
+
|
|
29
|
+
The function sets up the tracer provider, span processor and exporter with auto-instrumentation
|
|
30
|
+
|
|
31
|
+
:param app: The Flask Application
|
|
32
|
+
:param plugin: The plugin to derive the service name from
|
|
33
|
+
:param endpoint: The Otel Endpoint to emit traces to
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
if not is_running_in_cloud():
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
resource = Resource(attributes={"service.name": f'{plugin.name.lower().replace(" ", "_")}-{plugin.version}'})
|
|
40
|
+
|
|
41
|
+
trace_provider = TracerProvider(resource=resource)
|
|
42
|
+
exporter = OTLPSpanExporter(endpoint=endpoint)
|
|
43
|
+
trace_provider.add_span_processor(BatchSpanProcessor(exporter))
|
|
44
|
+
trace.set_tracer_provider(trace_provider)
|
|
45
|
+
|
|
46
|
+
FlaskInstrumentor().instrument_app(app)
|
|
47
|
+
|
|
48
|
+
def requests_callback(span: trace.Span, _: Any, response: Any) -> None:
|
|
49
|
+
if hasattr(response, "status_code"):
|
|
50
|
+
span.set_status(Status(StatusCode.OK if response.status_code < 400 else StatusCode.ERROR))
|
|
51
|
+
|
|
52
|
+
RequestsInstrumentor().instrument(trace_provider=trace_provider, response_hook=requests_callback)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def auto_instrument(func: Callable) -> Callable:
|
|
56
|
+
"""
|
|
57
|
+
Decorator that auto-instruments a function with a trace
|
|
58
|
+
|
|
59
|
+
:param func: function to instrument
|
|
60
|
+
:return:
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
@wraps(func)
|
|
64
|
+
def wrapper(*args, **kwargs):
|
|
65
|
+
tracer = trace.get_tracer(__name__)
|
|
66
|
+
with tracer.start_as_current_span(func.__name__):
|
|
67
|
+
return func(*args, **kwargs)
|
|
68
|
+
|
|
69
|
+
return wrapper
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def create_post_fork(app_getter: Callable, plugin_getter: Callable, config_getter: Callable) -> Callable:
|
|
73
|
+
def post_fork(server, worker):
|
|
74
|
+
app = app_getter()
|
|
75
|
+
plugin = plugin_getter()
|
|
76
|
+
endpoint = config_getter().get(OTEL_ENDPOINT, None)
|
|
77
|
+
if endpoint:
|
|
78
|
+
init_tracing(app, plugin, endpoint)
|
|
79
|
+
|
|
80
|
+
return post_fork
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def with_context(context: contextvars.Context, function: Callable) -> Callable:
|
|
84
|
+
"""
|
|
85
|
+
Creates a wrapper function that executes the target function with the specified context.
|
|
86
|
+
|
|
87
|
+
:param context: The Context object to apply when executing the function
|
|
88
|
+
:type context: contextvars.Context
|
|
89
|
+
|
|
90
|
+
:param function: The function to wrap with the specified context
|
|
91
|
+
:type function: Callable
|
|
92
|
+
|
|
93
|
+
:return: A wrapper function that applies the context when called
|
|
94
|
+
:rtype: Callable
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
def _wrapper(context_: contextvars.Context, function_: Callable, *args, **kwargs):
|
|
98
|
+
return context_.copy().run(function_, *args, **kwargs)
|
|
99
|
+
|
|
100
|
+
return partial(_wrapper, context, function)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def monitor_task_delay(
|
|
104
|
+
timestamp_keys: Union[str, List[str]], default_delay_threshold: str = "2d"
|
|
105
|
+
) -> Callable:
|
|
106
|
+
"""Monitor timestamp fields in task state to detect processing delays.
|
|
107
|
+
|
|
108
|
+
This decorator checks if specified timestamp fields in a task's state have fallen
|
|
109
|
+
behind a configurable threshold, indicating the task is processing data with a lag.
|
|
110
|
+
When timestamps fall behind the threshold, an error is logged.
|
|
111
|
+
|
|
112
|
+
The threshold can be overridden at runtime by setting the "task_delay_threshold" key
|
|
113
|
+
in the task's custom_config.
|
|
114
|
+
|
|
115
|
+
:param timestamp_keys: One or more state keys containing timestamps to monitor
|
|
116
|
+
:type timestamp_keys: Union[str, List[str]]
|
|
117
|
+
|
|
118
|
+
:param default_delay_threshold: Time duration string representing maximum acceptable lag (e.g. "2d" for 2 days).
|
|
119
|
+
:type default_delay_threshold: str
|
|
120
|
+
|
|
121
|
+
:return: Decorator function that wraps the original task function
|
|
122
|
+
:rtype: Callable
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
# Check if time_fields is a string and convert it to a list
|
|
126
|
+
if isinstance(timestamp_keys, str):
|
|
127
|
+
timestamp_keys = [timestamp_keys]
|
|
128
|
+
|
|
129
|
+
def _decorator(function_: Callable):
|
|
130
|
+
@wraps(function_)
|
|
131
|
+
def _wrapper(self, *args, **kwargs):
|
|
132
|
+
# Unpack response tuple from task `def run()` method
|
|
133
|
+
output, state, has_more_pages, status_code, error_object = function_(
|
|
134
|
+
self, *args, **kwargs
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Try-except with pass to make sure any exception won't stop the task from running
|
|
138
|
+
try:
|
|
139
|
+
# Check if any time fields are in the past
|
|
140
|
+
threshold = kwargs.get("custom_config", {}).get(
|
|
141
|
+
"task_delay_threshold", default_delay_threshold
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Calculate the delayed time based on the threshold
|
|
145
|
+
delay_threshold_time = (
|
|
146
|
+
datetime.now(UTC) - parse_from_string(threshold)
|
|
147
|
+
).replace(tzinfo=None)
|
|
148
|
+
|
|
149
|
+
# Loop over the state time fields and check if they are below the set threshold
|
|
150
|
+
for state_time in timestamp_keys:
|
|
151
|
+
# Check if the state time exists in the state dictionary
|
|
152
|
+
if not (current_state_time := state.get(state_time)):
|
|
153
|
+
continue
|
|
154
|
+
|
|
155
|
+
# Parse and normalize the state time value
|
|
156
|
+
try:
|
|
157
|
+
# First, try to parse the epoch timestamp
|
|
158
|
+
normalized_state_time = datetime.fromtimestamp(
|
|
159
|
+
float(current_state_time)
|
|
160
|
+
)
|
|
161
|
+
except (ValueError, TypeError):
|
|
162
|
+
# If parsing fails, parse as a string
|
|
163
|
+
normalized_state_time = parse(str(current_state_time))
|
|
164
|
+
|
|
165
|
+
# Normalize the state time to UTC and remove timezone info
|
|
166
|
+
normalized_state_time = normalized_state_time.astimezone(
|
|
167
|
+
UTC
|
|
168
|
+
).replace(tzinfo=None)
|
|
169
|
+
|
|
170
|
+
# If the normalized state time is below the threshold, log an error message
|
|
171
|
+
if normalized_state_time < delay_threshold_time:
|
|
172
|
+
# Log an error message that indicates the integration state time is below the threshold
|
|
173
|
+
self.logger.error(
|
|
174
|
+
f"ERROR: THE INTEGRATION IS FALLING BEHIND",
|
|
175
|
+
field=state_time,
|
|
176
|
+
current_value=current_state_time,
|
|
177
|
+
normalized_time=normalized_state_time,
|
|
178
|
+
threshold_time=delay_threshold_time,
|
|
179
|
+
configured_threshold=threshold,
|
|
180
|
+
has_more_pages=has_more_pages,
|
|
181
|
+
)
|
|
182
|
+
break
|
|
183
|
+
except Exception as error:
|
|
184
|
+
self.logger.info(
|
|
185
|
+
f"An error occurred while checking task delay. Error: {error}"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Return task output
|
|
189
|
+
return output, state, has_more_pages, status_code, error_object
|
|
190
|
+
|
|
191
|
+
return _wrapper
|
|
192
|
+
|
|
193
|
+
return _decorator
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
import copy
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
|
+
import re
|
|
5
6
|
import sys
|
|
7
|
+
from datetime import timedelta
|
|
6
8
|
from typing import Any, Dict, List, Tuple, Union
|
|
7
9
|
|
|
8
10
|
import python_jsonschema_objects as pjs
|
|
@@ -261,3 +263,44 @@ def trace():
|
|
|
261
263
|
|
|
262
264
|
def is_running_in_cloud():
|
|
263
265
|
return os.environ.get("PLUGIN_RUNTIME_ENVIRONMENT") == "cloud"
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def parse_from_string(
|
|
269
|
+
duration: str,
|
|
270
|
+
default: timedelta = timedelta(days=2),
|
|
271
|
+
unit_map: Dict[str, str] = None,
|
|
272
|
+
) -> timedelta:
|
|
273
|
+
"""
|
|
274
|
+
Parse a string duration (i.e. '5d', '12h', '30m', '45s') into a timedelta object.
|
|
275
|
+
|
|
276
|
+
:param duration: String in format like '5d', '12h', '30m', '45s'
|
|
277
|
+
:type duration: str
|
|
278
|
+
|
|
279
|
+
:param default: Default timedelta to return if parsing fails
|
|
280
|
+
:type default: timedelta
|
|
281
|
+
|
|
282
|
+
:param unit_map: Mapping of unit letters to timedelta parameter names
|
|
283
|
+
:type unit_map: Dict[str, str]
|
|
284
|
+
|
|
285
|
+
:return: Parsed timedelta or default if parsing fails
|
|
286
|
+
:rtype: timedelta
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
# If unit_map is not provided, use the default mapping
|
|
290
|
+
if unit_map is None:
|
|
291
|
+
unit_map = {"s": "seconds", "m": "minutes", "h": "hours", "d": "days"}
|
|
292
|
+
|
|
293
|
+
# Check if duration is not empty and is a string
|
|
294
|
+
if not duration or not isinstance(duration, str):
|
|
295
|
+
return default
|
|
296
|
+
|
|
297
|
+
# Use regex to match the duration format
|
|
298
|
+
match = re.match(r"(\d+)([smhd])", duration.lower())
|
|
299
|
+
if not match:
|
|
300
|
+
return default
|
|
301
|
+
|
|
302
|
+
# If match is found, extract the value and unit
|
|
303
|
+
value, unit = match.groups()
|
|
304
|
+
|
|
305
|
+
# Return a timedelta object based on the matched value and unit from the unit_map
|
|
306
|
+
return timedelta(**{unit_map[unit]: int(value)})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: insightconnect-plugin-runtime
|
|
3
|
-
Version: 6.3.
|
|
3
|
+
Version: 6.3.6
|
|
4
4
|
Summary: InsightConnect Plugin Runtime
|
|
5
5
|
Home-page: https://github.com/rapid7/komand-plugin-sdk-python
|
|
6
6
|
Author: Rapid7 Integrations Alliance
|
|
@@ -12,25 +12,26 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
12
12
|
Classifier: Natural Language :: English
|
|
13
13
|
Classifier: Topic :: Software Development :: Build Tools
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
-
Requires-Dist: requests==2.32.
|
|
15
|
+
Requires-Dist: requests==2.32.4
|
|
16
16
|
Requires-Dist: python_jsonschema_objects==0.5.2
|
|
17
17
|
Requires-Dist: jsonschema==4.22.0
|
|
18
|
-
Requires-Dist: certifi==
|
|
18
|
+
Requires-Dist: certifi==2025.4.26
|
|
19
19
|
Requires-Dist: Flask==3.1.1
|
|
20
20
|
Requires-Dist: gunicorn==23.0.0
|
|
21
|
-
Requires-Dist: greenlet==3.
|
|
22
|
-
Requires-Dist: gevent==
|
|
21
|
+
Requires-Dist: greenlet==3.2.3
|
|
22
|
+
Requires-Dist: gevent==25.5.1
|
|
23
23
|
Requires-Dist: marshmallow==3.21.0
|
|
24
24
|
Requires-Dist: apispec==6.5.0
|
|
25
25
|
Requires-Dist: apispec-webframeworks==1.0.0
|
|
26
26
|
Requires-Dist: blinker==1.9.0
|
|
27
|
-
Requires-Dist: structlog==
|
|
27
|
+
Requires-Dist: structlog==25.4.0
|
|
28
28
|
Requires-Dist: python-json-logger==2.0.7
|
|
29
29
|
Requires-Dist: Jinja2==3.1.6
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-Dist: opentelemetry-
|
|
32
|
-
Requires-Dist: opentelemetry-
|
|
33
|
-
Requires-Dist: opentelemetry-
|
|
30
|
+
Requires-Dist: python-dateutil==2.9.0.post0
|
|
31
|
+
Requires-Dist: opentelemetry-sdk==1.34.0
|
|
32
|
+
Requires-Dist: opentelemetry-instrumentation-flask==0.55b0
|
|
33
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.34.0
|
|
34
|
+
Requires-Dist: opentelemetry-instrumentation-requests==0.55b0
|
|
34
35
|
Dynamic: author
|
|
35
36
|
Dynamic: author-email
|
|
36
37
|
Dynamic: classifier
|
|
@@ -224,6 +225,8 @@ contributed. Black is installed as a test dependency and the hook can be initial
|
|
|
224
225
|
after cloning this repository.
|
|
225
226
|
|
|
226
227
|
## Changelog
|
|
228
|
+
* 6.3.6 - Added required dependency to plugin runtime
|
|
229
|
+
* 6.3.5 - Added `monitor_task_delay` decorator to detect processing delays
|
|
227
230
|
* 6.3.4 - Addressed vulnerabilities within the slim and non-slim Python images (bumping packages)
|
|
228
231
|
* 6.3.3 - Add helper func for tracing context to preserve parent span in threadpools
|
|
229
232
|
* 6.3.2 - Raise `APIException` from within the `response_handler` to easily access the status code within the plugin
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
requests==2.32.4
|
|
2
|
+
python_jsonschema_objects==0.5.2
|
|
3
|
+
jsonschema==4.22.0
|
|
4
|
+
certifi==2025.4.26
|
|
5
|
+
Flask==3.1.1
|
|
6
|
+
gunicorn==23.0.0
|
|
7
|
+
greenlet==3.2.3
|
|
8
|
+
gevent==25.5.1
|
|
9
|
+
marshmallow==3.21.0
|
|
10
|
+
apispec==6.5.0
|
|
11
|
+
apispec-webframeworks==1.0.0
|
|
12
|
+
blinker==1.9.0
|
|
13
|
+
structlog==25.4.0
|
|
14
|
+
python-json-logger==2.0.7
|
|
15
|
+
Jinja2==3.1.6
|
|
16
|
+
python-dateutil==2.9.0.post0
|
|
17
|
+
opentelemetry-sdk==1.34.0
|
|
18
|
+
opentelemetry-instrumentation-flask==0.55b0
|
|
19
|
+
opentelemetry-exporter-otlp-proto-http==1.34.0
|
|
20
|
+
opentelemetry-instrumentation-requests==0.55b0
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="insightconnect-plugin-runtime",
|
|
8
|
-
version="6.3.
|
|
8
|
+
version="6.3.6",
|
|
9
9
|
description="InsightConnect Plugin Runtime",
|
|
10
10
|
long_description=long_description,
|
|
11
11
|
long_description_content_type="text/markdown",
|
|
@@ -14,25 +14,26 @@ setup(
|
|
|
14
14
|
url="https://github.com/rapid7/komand-plugin-sdk-python",
|
|
15
15
|
packages=find_packages(),
|
|
16
16
|
install_requires=[
|
|
17
|
-
"requests==2.32.
|
|
17
|
+
"requests==2.32.4",
|
|
18
18
|
"python_jsonschema_objects==0.5.2",
|
|
19
19
|
"jsonschema==4.22.0",
|
|
20
|
-
"certifi==
|
|
20
|
+
"certifi==2025.4.26",
|
|
21
21
|
"Flask==3.1.1",
|
|
22
22
|
"gunicorn==23.0.0",
|
|
23
|
-
"greenlet==3.
|
|
24
|
-
"gevent==
|
|
23
|
+
"greenlet==3.2.3",
|
|
24
|
+
"gevent==25.5.1",
|
|
25
25
|
"marshmallow==3.21.0",
|
|
26
26
|
"apispec==6.5.0",
|
|
27
27
|
"apispec-webframeworks==1.0.0",
|
|
28
28
|
"blinker==1.9.0",
|
|
29
|
-
"structlog==
|
|
29
|
+
"structlog==25.4.0",
|
|
30
30
|
"python-json-logger==2.0.7",
|
|
31
31
|
"Jinja2==3.1.6",
|
|
32
|
-
"
|
|
33
|
-
"opentelemetry-
|
|
34
|
-
"opentelemetry-
|
|
35
|
-
"opentelemetry-
|
|
32
|
+
"python-dateutil==2.9.0.post0",
|
|
33
|
+
"opentelemetry-sdk==1.34.0",
|
|
34
|
+
"opentelemetry-instrumentation-flask==0.55b0",
|
|
35
|
+
"opentelemetry-exporter-otlp-proto-http==1.34.0",
|
|
36
|
+
"opentelemetry-instrumentation-requests==0.55b0",
|
|
36
37
|
],
|
|
37
38
|
tests_require=[
|
|
38
39
|
"pytest",
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import contextvars
|
|
2
|
-
from functools import wraps, partial
|
|
3
|
-
from typing import Any, Callable
|
|
4
|
-
|
|
5
|
-
from flask.app import Flask
|
|
6
|
-
from opentelemetry import trace
|
|
7
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
8
|
-
from opentelemetry.instrumentation.flask import FlaskInstrumentor
|
|
9
|
-
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
|
10
|
-
from opentelemetry.sdk.resources import Resource
|
|
11
|
-
from opentelemetry.sdk.trace import TracerProvider
|
|
12
|
-
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
13
|
-
from opentelemetry.trace import Status, StatusCode
|
|
14
|
-
|
|
15
|
-
from insightconnect_plugin_runtime.plugin import Plugin
|
|
16
|
-
from insightconnect_plugin_runtime.util import is_running_in_cloud, OTEL_ENDPOINT
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def init_tracing(app: Flask, plugin: Plugin, endpoint: str) -> None:
|
|
20
|
-
"""
|
|
21
|
-
Initialize OpenTelemetry Tracing
|
|
22
|
-
|
|
23
|
-
The function sets up the tracer provider, span processor and exporter with auto-instrumentation
|
|
24
|
-
|
|
25
|
-
:param app: The Flask Application
|
|
26
|
-
:param plugin: The plugin to derive the service name from
|
|
27
|
-
:param endpoint: The Otel Endpoint to emit traces to
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
if not is_running_in_cloud():
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
resource = Resource(attributes={"service.name": f'{plugin.name.lower().replace(" ", "_")}-{plugin.version}'})
|
|
34
|
-
|
|
35
|
-
trace_provider = TracerProvider(resource=resource)
|
|
36
|
-
exporter = OTLPSpanExporter(endpoint=endpoint)
|
|
37
|
-
trace_provider.add_span_processor(BatchSpanProcessor(exporter))
|
|
38
|
-
trace.set_tracer_provider(trace_provider)
|
|
39
|
-
|
|
40
|
-
FlaskInstrumentor().instrument_app(app)
|
|
41
|
-
|
|
42
|
-
def requests_callback(span: trace.Span, _: Any, response: Any) -> None:
|
|
43
|
-
if hasattr(response, "status_code"):
|
|
44
|
-
span.set_status(Status(StatusCode.OK if response.status_code < 400 else StatusCode.ERROR))
|
|
45
|
-
|
|
46
|
-
RequestsInstrumentor().instrument(trace_provider=trace_provider, response_hook=requests_callback)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def auto_instrument(func: Callable) -> Callable:
|
|
50
|
-
"""
|
|
51
|
-
Decorator that auto-instruments a function with a trace
|
|
52
|
-
|
|
53
|
-
:param func: function to instrument
|
|
54
|
-
:return:
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
@wraps(func)
|
|
58
|
-
def wrapper(*args, **kwargs):
|
|
59
|
-
tracer = trace.get_tracer(__name__)
|
|
60
|
-
with tracer.start_as_current_span(func.__name__):
|
|
61
|
-
return func(*args, **kwargs)
|
|
62
|
-
|
|
63
|
-
return wrapper
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def create_post_fork(app_getter: Callable, plugin_getter: Callable, config_getter: Callable) -> Callable:
|
|
67
|
-
def post_fork(server, worker):
|
|
68
|
-
app = app_getter()
|
|
69
|
-
plugin = plugin_getter()
|
|
70
|
-
endpoint = config_getter().get(OTEL_ENDPOINT, None)
|
|
71
|
-
if endpoint:
|
|
72
|
-
init_tracing(app, plugin, endpoint)
|
|
73
|
-
|
|
74
|
-
return post_fork
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def with_context(context: contextvars.Context, function: Callable) -> Callable:
|
|
78
|
-
"""
|
|
79
|
-
Creates a wrapper function that executes the target function with the specified context.
|
|
80
|
-
|
|
81
|
-
:param context: The Context object to apply when executing the function
|
|
82
|
-
:type context: contextvars.Context
|
|
83
|
-
|
|
84
|
-
:param function: The function to wrap with the specified context
|
|
85
|
-
:type function: Callable
|
|
86
|
-
|
|
87
|
-
:return: A wrapper function that applies the context when called
|
|
88
|
-
:rtype: Callable
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
def _wrapper(context_: contextvars.Context, function_: Callable, *args, **kwargs):
|
|
92
|
-
return context_.copy().run(function_, *args, **kwargs)
|
|
93
|
-
|
|
94
|
-
return partial(_wrapper, context, function)
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
requests==2.32.3
|
|
2
|
-
python_jsonschema_objects==0.5.2
|
|
3
|
-
jsonschema==4.22.0
|
|
4
|
-
certifi==2024.12.14
|
|
5
|
-
Flask==3.1.1
|
|
6
|
-
gunicorn==23.0.0
|
|
7
|
-
greenlet==3.1.1
|
|
8
|
-
gevent==24.11.1
|
|
9
|
-
marshmallow==3.21.0
|
|
10
|
-
apispec==6.5.0
|
|
11
|
-
apispec-webframeworks==1.0.0
|
|
12
|
-
blinker==1.9.0
|
|
13
|
-
structlog==24.4.0
|
|
14
|
-
python-json-logger==2.0.7
|
|
15
|
-
Jinja2==3.1.6
|
|
16
|
-
opentelemetry-sdk==1.31.1
|
|
17
|
-
opentelemetry-instrumentation-flask==0.52b1
|
|
18
|
-
opentelemetry-exporter-otlp-proto-http==1.31.1
|
|
19
|
-
opentelemetry-instrumentation-requests==0.52b1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/__init__.py
RENAMED
|
File without changes
|
{insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/plugin/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/test_oauth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightconnect_plugin_runtime-6.3.4 → insightconnect_plugin_runtime-6.3.6}/tests/unit/utils.py
RENAMED
|
File without changes
|