pyoaev 1.18.20__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. docs/conf.py +65 -0
  2. pyoaev/__init__.py +26 -0
  3. pyoaev/_version.py +6 -0
  4. pyoaev/apis/__init__.py +20 -0
  5. pyoaev/apis/attack_pattern.py +28 -0
  6. pyoaev/apis/collector.py +29 -0
  7. pyoaev/apis/cve.py +18 -0
  8. pyoaev/apis/document.py +29 -0
  9. pyoaev/apis/endpoint.py +38 -0
  10. pyoaev/apis/inject.py +29 -0
  11. pyoaev/apis/inject_expectation/__init__.py +1 -0
  12. pyoaev/apis/inject_expectation/inject_expectation.py +118 -0
  13. pyoaev/apis/inject_expectation/model/__init__.py +7 -0
  14. pyoaev/apis/inject_expectation/model/expectation.py +173 -0
  15. pyoaev/apis/inject_expectation_trace.py +36 -0
  16. pyoaev/apis/injector.py +26 -0
  17. pyoaev/apis/injector_contract.py +56 -0
  18. pyoaev/apis/inputs/__init__.py +0 -0
  19. pyoaev/apis/inputs/search.py +72 -0
  20. pyoaev/apis/kill_chain_phase.py +22 -0
  21. pyoaev/apis/me.py +17 -0
  22. pyoaev/apis/organization.py +11 -0
  23. pyoaev/apis/payload.py +27 -0
  24. pyoaev/apis/security_platform.py +33 -0
  25. pyoaev/apis/tag.py +19 -0
  26. pyoaev/apis/team.py +25 -0
  27. pyoaev/apis/user.py +31 -0
  28. pyoaev/backends/__init__.py +14 -0
  29. pyoaev/backends/backend.py +136 -0
  30. pyoaev/backends/protocol.py +32 -0
  31. pyoaev/base.py +320 -0
  32. pyoaev/client.py +596 -0
  33. pyoaev/configuration/__init__.py +3 -0
  34. pyoaev/configuration/configuration.py +188 -0
  35. pyoaev/configuration/sources.py +44 -0
  36. pyoaev/contracts/__init__.py +5 -0
  37. pyoaev/contracts/contract_builder.py +44 -0
  38. pyoaev/contracts/contract_config.py +292 -0
  39. pyoaev/contracts/contract_utils.py +22 -0
  40. pyoaev/contracts/variable_helper.py +124 -0
  41. pyoaev/daemons/__init__.py +4 -0
  42. pyoaev/daemons/base_daemon.py +131 -0
  43. pyoaev/daemons/collector_daemon.py +91 -0
  44. pyoaev/exceptions.py +219 -0
  45. pyoaev/helpers.py +451 -0
  46. pyoaev/mixins.py +242 -0
  47. pyoaev/signatures/__init__.py +0 -0
  48. pyoaev/signatures/signature_match.py +12 -0
  49. pyoaev/signatures/signature_type.py +51 -0
  50. pyoaev/signatures/types.py +17 -0
  51. pyoaev/utils.py +211 -0
  52. pyoaev-1.18.20.dist-info/METADATA +134 -0
  53. pyoaev-1.18.20.dist-info/RECORD +72 -0
  54. pyoaev-1.18.20.dist-info/WHEEL +5 -0
  55. pyoaev-1.18.20.dist-info/licenses/LICENSE +201 -0
  56. pyoaev-1.18.20.dist-info/top_level.txt +4 -0
  57. scripts/release.py +127 -0
  58. test/__init__.py +0 -0
  59. test/apis/__init__.py +0 -0
  60. test/apis/expectation/__init__.py +0 -0
  61. test/apis/expectation/test_expectation.py +338 -0
  62. test/apis/injector_contract/__init__.py +0 -0
  63. test/apis/injector_contract/test_injector_contract.py +58 -0
  64. test/configuration/__init__.py +0 -0
  65. test/configuration/test_configuration.py +257 -0
  66. test/configuration/test_sources.py +69 -0
  67. test/daemons/__init__.py +0 -0
  68. test/daemons/test_base_daemon.py +109 -0
  69. test/daemons/test_collector_daemon.py +39 -0
  70. test/signatures/__init__.py +0 -0
  71. test/signatures/test_signature_match.py +25 -0
  72. test/signatures/test_signature_type.py +57 -0
@@ -0,0 +1,51 @@
1
+ from pyoaev.signatures.signature_match import SignatureMatch
2
+ from pyoaev.signatures.types import MatchTypes, SignatureTypes
3
+
4
+
5
+ class SignatureType:
6
+ """Describes a signature of some time and a matching policy
7
+
8
+ :param label: Type specifier
9
+ :type label: SignatureTypes
10
+ :param match_type: the matching policy to use when trying
11
+ to match this signature type, e.g. fuzzy, simple...
12
+ :type match_type: MatchTypes
13
+ :param match_score: if the matching type is fuzzy, this is
14
+ the score to use as threshold, defaults to None
15
+ :type match_score: int, optional
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ label: SignatureTypes,
21
+ match_type: MatchTypes = MatchTypes.MATCH_TYPE_SIMPLE,
22
+ match_score: int = None,
23
+ ):
24
+ self.label = label
25
+ self.match_policy = SignatureMatch(match_type, match_score)
26
+
27
+ def make_struct_for_matching(self, data):
28
+ """Provided some `data`, formats a dictionary specifying the matching
29
+ policy to use by the helper to match expected signatures (from expectations)
30
+ with actual, alert signatures (from the security software)
31
+
32
+ :param data: arbitrary data, but most often string or a number primitive
33
+ :type: Any
34
+
35
+ :return: dictionary of matching specifiers::
36
+ {
37
+ "type": str,
38
+ "data": any,
39
+ "score": (optional) int
40
+ }
41
+ :rtype: dict
42
+ """
43
+ struct = {
44
+ "type": self.match_policy.match_type.value,
45
+ "data": data,
46
+ }
47
+
48
+ if self.match_policy.match_score is not None:
49
+ struct["score"] = self.match_policy.match_score
50
+
51
+ return struct
@@ -0,0 +1,17 @@
1
+ from enum import Enum
2
+
3
+
4
+ class MatchTypes(str, Enum):
5
+ MATCH_TYPE_FUZZY = "fuzzy"
6
+ MATCH_TYPE_SIMPLE = "simple"
7
+
8
+
9
+ class SignatureTypes(str, Enum):
10
+ SIG_TYPE_PARENT_PROCESS_NAME = "parent_process_name"
11
+ SIG_TYPE_SOURCE_IPV4_ADDRESS = "source_ipv4_address"
12
+ SIG_TYPE_SOURCE_IPV6_ADDRESS = "source_ipv6_address"
13
+ SIG_TYPE_TARGET_IPV4_ADDRESS = "target_ipv4_address"
14
+ SIG_TYPE_TARGET_IPV6_ADDRESS = "target_ipv6_address"
15
+ SIG_TYPE_TARGET_HOSTNAME_ADDRESS = "target_hostname_address"
16
+ SIG_TYPE_START_DATE = "start_date"
17
+ SIG_TYPE_END_DATE = "end_date"
pyoaev/utils.py ADDED
@@ -0,0 +1,211 @@
1
+ import dataclasses
2
+ import datetime
3
+ import email.message
4
+ import json
5
+ import logging
6
+ import threading
7
+ import urllib.parse
8
+ from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, Union
9
+
10
+ import requests
11
+ from pythonjsonlogger import jsonlogger
12
+
13
+
14
+ class _StdoutStream:
15
+ def __call__(self, chunk: Any) -> None:
16
+ print(chunk)
17
+
18
+
19
+ def get_content_type(content_type: Optional[str]) -> str:
20
+ message = email.message.Message()
21
+ message["content-type"] = content_type
22
+
23
+ return message.get_content_type()
24
+
25
+
26
+ def response_content(
27
+ response: requests.Response,
28
+ streamed: bool,
29
+ action: Optional[Callable[[bytes], None]],
30
+ chunk_size: int,
31
+ *,
32
+ iterator: bool,
33
+ ) -> Optional[Union[bytes, Iterator[Any]]]:
34
+ if iterator:
35
+ return response.iter_content(chunk_size=chunk_size)
36
+
37
+ if streamed is False:
38
+ return response.content
39
+
40
+ if action is None:
41
+ action = _StdoutStream()
42
+
43
+ for chunk in response.iter_content(chunk_size=chunk_size):
44
+ if chunk:
45
+ action(chunk)
46
+ return None
47
+
48
+
49
+ def copy_dict(
50
+ *,
51
+ src: Dict[str, Any],
52
+ dest: Dict[str, Any],
53
+ ) -> None:
54
+ for k, v in src.items():
55
+ if isinstance(v, dict):
56
+ for dict_k, dict_v in v.items():
57
+ dest[f"{k}[{dict_k}]"] = dict_v
58
+ else:
59
+ dest[k] = v
60
+
61
+
62
+ class EncodedId(str):
63
+ def __new__(cls, value: Union[str, int, "EncodedId"]) -> "EncodedId":
64
+ if isinstance(value, EncodedId):
65
+ return value
66
+
67
+ if not isinstance(value, (int, str)):
68
+ raise TypeError(f"Unsupported type received: {type(value)}")
69
+ if isinstance(value, str):
70
+ value = urllib.parse.quote(value, safe="")
71
+ return super().__new__(cls, value)
72
+
73
+
74
+ def remove_none_from_dict(data: Dict[str, Any]) -> Dict[str, Any]:
75
+ return {k: v for k, v in data.items() if v is not None}
76
+
77
+
78
+ class EnhancedJSONEncoder(json.JSONEncoder):
79
+ def default(self, o):
80
+ if dataclasses.is_dataclass(o):
81
+ return dataclasses.asdict(o)
82
+ return super().default(o)
83
+
84
+
85
+ @dataclasses.dataclass(frozen=True)
86
+ class RequiredOptional:
87
+ required: Tuple[str, ...] = ()
88
+ optional: Tuple[str, ...] = ()
89
+ exclusive: Tuple[str, ...] = ()
90
+
91
+ def validate_attrs(
92
+ self,
93
+ *,
94
+ data: Dict[str, Any],
95
+ excludes: Optional[List[str]] = None,
96
+ ) -> None:
97
+ if excludes is None:
98
+ excludes = []
99
+
100
+ if self.required:
101
+ required = [k for k in self.required if k not in excludes]
102
+ missing = [attr for attr in required if attr not in data]
103
+ if missing:
104
+ raise AttributeError(f"Missing attributes: {', '.join(missing)}")
105
+
106
+ if self.exclusive:
107
+ exclusives = [attr for attr in data if attr in self.exclusive]
108
+ if len(exclusives) > 1:
109
+ raise AttributeError(
110
+ f"Provide only one of these attributes: {', '.join(exclusives)}"
111
+ )
112
+ if not exclusives:
113
+ raise AttributeError(
114
+ f"Must provide one of these attributes: "
115
+ f"{', '.join(self.exclusive)}"
116
+ )
117
+
118
+
119
+ class CustomJsonFormatter(jsonlogger.JsonFormatter):
120
+ def add_fields(self, log_record, record, message_dict):
121
+ super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)
122
+ if not log_record.get("timestamp"):
123
+ # This doesn't use record.created, so it is slightly off
124
+ now = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
125
+ log_record["timestamp"] = now
126
+ if log_record.get("level"):
127
+ log_record["level"] = log_record["level"].upper()
128
+ else:
129
+ log_record["level"] = record.levelname
130
+
131
+
132
+ def setup_logging_config(level, json_logging=True):
133
+ logging.getLogger("urllib3").setLevel(logging.WARNING)
134
+ logging.getLogger("pika").setLevel(logging.ERROR)
135
+ # Exceptions
136
+ if json_logging:
137
+ log_handler = logging.StreamHandler()
138
+ log_handler.setLevel(level)
139
+ formatter = CustomJsonFormatter("%(timestamp)s %(level)s %(name)s %(message)s")
140
+ log_handler.setFormatter(formatter)
141
+ logging.basicConfig(handlers=[log_handler], level=level, force=True)
142
+ else:
143
+ logging.basicConfig(level=level)
144
+
145
+
146
+ class AppLogger:
147
+ def __init__(self, level, json_logging=True, name: str = __name__):
148
+ self.log_level = level
149
+ self.json_logging = json_logging
150
+ setup_logging_config(self.log_level, self.json_logging)
151
+ self.local_logger = logging.getLogger(name)
152
+
153
+ def __call__(self, name):
154
+ self.local_logger = logging.getLogger(name)
155
+ return self
156
+
157
+ @staticmethod
158
+ def prepare_meta(meta=None):
159
+ return None if meta is None else {"attributes": meta}
160
+
161
+ @staticmethod
162
+ def setup_logger_level(lib, log_level):
163
+ logging.getLogger(lib).setLevel(log_level)
164
+
165
+ def debug(self, message, meta=None):
166
+ self.local_logger.debug(message, extra=AppLogger.prepare_meta(meta))
167
+
168
+ def info(self, message, meta=None):
169
+ self.local_logger.info(message, extra=AppLogger.prepare_meta(meta))
170
+
171
+ def warning(self, message, meta=None):
172
+ self.local_logger.warning(message, extra=AppLogger.prepare_meta(meta))
173
+
174
+ def error(self, message, meta=None):
175
+ # noinspection PyTypeChecker
176
+ self.local_logger.error(message, exc_info=1, extra=AppLogger.prepare_meta(meta))
177
+
178
+
179
+ # DEPRECATED: compatibility
180
+ def logger(level, json_logging=True):
181
+ return AppLogger(level, json_logging)
182
+
183
+
184
+ class PingAlive(threading.Thread):
185
+ def __init__(self, api, config, logger, ping_type) -> None:
186
+ threading.Thread.__init__(self)
187
+ self.ping_type = ping_type
188
+ self.api = api
189
+ self.config = config
190
+ self.logger = logger
191
+ self.in_error = False
192
+ self.exit_event = threading.Event()
193
+
194
+ def ping(self) -> None:
195
+ while not self.exit_event.is_set():
196
+ try:
197
+ if self.ping_type == "injector":
198
+ self.api.injector.create(self.config, False)
199
+ else:
200
+ self.api.collector.create(self.config, False)
201
+ except Exception as err: # pylint: disable=broad-except
202
+ self.logger.error("Error pinging the API: " + str(err))
203
+ self.exit_event.wait(40)
204
+
205
+ def run(self) -> None:
206
+ self.logger.info("Starting PingAlive thread")
207
+ self.ping()
208
+
209
+ def stop(self) -> None:
210
+ self.logger.info("Preparing PingAlive for clean shutdown")
211
+ self.exit_event.set()
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyoaev
3
+ Version: 1.18.20
4
+ Summary: Python API client for OpenAEV.
5
+ Author-email: Filigran <contact@filigran.io>
6
+ Maintainer-email: Filigran <contact@filigran.io>
7
+ License: Apache-2.0
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Information Technology
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Natural Language :: French
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Topic :: Security
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: datefinder<0.8,>=0.7.3
23
+ Requires-Dist: pika<1.4.0,>=1.3.0
24
+ Requires-Dist: python-magic<0.5,>=0.4.27; sys_platform == "linux" or sys_platform == "darwin"
25
+ Requires-Dist: python-magic-bin<0.5,>=0.4.14; sys_platform == "win32"
26
+ Requires-Dist: python_json_logger<3.4.0,>=3.3.0
27
+ Requires-Dist: PyYAML<6.1,>=6.0
28
+ Requires-Dist: pydantic<2.12.0,>=2.11.3
29
+ Requires-Dist: requests<2.33.0,>=2.32.3
30
+ Requires-Dist: setuptools<80.10.0,>=80.9.0
31
+ Requires-Dist: cachetools<5.6.0,>=5.5.0
32
+ Requires-Dist: prometheus-client<0.23.0,>=0.22.1
33
+ Requires-Dist: opentelemetry-api<1.36.0,>=1.35.0
34
+ Requires-Dist: opentelemetry-sdk<1.36.0,>=1.35.0
35
+ Requires-Dist: requests-toolbelt<1.1.0,>=1.0.0
36
+ Requires-Dist: dataclasses-json<0.7.0,>=0.6.4
37
+ Requires-Dist: thefuzz<0.23,>=0.22
38
+ Provides-Extra: dev
39
+ Requires-Dist: black<25.2.0,>=25.1.0; extra == "dev"
40
+ Requires-Dist: build<1.3.0,>=1.2.1; extra == "dev"
41
+ Requires-Dist: isort<6.1.0,>=6.0.0; extra == "dev"
42
+ Requires-Dist: types-pytz<2025.3.0.0,>=2025.2.0.20250326; extra == "dev"
43
+ Requires-Dist: pre-commit<4.3.0,>=4.2.0; extra == "dev"
44
+ Requires-Dist: types-python-dateutil<2.10.0,>=2.9.0; extra == "dev"
45
+ Requires-Dist: wheel<0.46.0,>=0.45.1; extra == "dev"
46
+ Provides-Extra: doc
47
+ Requires-Dist: autoapi<2.1.0,>=2.0.1; extra == "doc"
48
+ Requires-Dist: sphinx-autodoc-typehints<3.3.0,>=3.2.0; extra == "doc"
49
+ Requires-Dist: sphinx-rtd-theme<3.1.0,>=3.0.2; extra == "doc"
50
+ Dynamic: license-file
51
+
52
+ # OpenAEV client for Python
53
+
54
+ [![Website](https://img.shields.io/badge/website-openaev.io-blue.svg)](https://openaev.io)
55
+ [![CircleCI](https://circleci.com/gh/OpenAEV-Platform/client-python.svg?style=shield)](https://circleci.com/gh/OpenAEV-Platform/client-python/tree/main)
56
+ [![readthedocs](https://readthedocs.org/projects/openaev-client-for-python/badge/?style=flat)](https://openaev-client-for-python.readthedocs.io/en/latest/)
57
+ [![GitHub release](https://img.shields.io/github/release/OpenAEV-Platform/client-python.svg)](https://github.com/OpenAEV-Platform/client-python/releases/latest)
58
+ [![Number of PyPI downloads](https://img.shields.io/pypi/dm/pyoaev.svg)](https://pypi.python.org/pypi/pyoaev/)
59
+ [![Slack Status](https://img.shields.io/badge/slack-3K%2B%20members-4A154B)](https://community.filigran.io)
60
+
61
+ The official OpenAEV Python client helps developers to use the OpenAEV API by providing easy to use methods and utils.
62
+ This client is also used by some OpenAEV components.
63
+
64
+ ## Install
65
+
66
+ To install the latest Python client library, please use `pip`:
67
+
68
+ ```bash
69
+ $ pip3 install pyoaev
70
+ ```
71
+
72
+ ## Local development
73
+
74
+ ```bash
75
+ # Fork the current repository, then clone your fork
76
+ $ git clone https://github.com/YOUR-USERNAME/client-python
77
+ $ cd client-python
78
+ $ git remote add upstream https://github.com/OpenAEV-Platform/client-python.git
79
+ # Create a branch for your feature/fix
80
+ $ git checkout -b [branch-name]
81
+ # Create a virtualenv
82
+ $ python3 -m venv .venv
83
+ $ source .venv/bin/activate
84
+ # Install the client-python and dependencies for the development and the documentation
85
+ $ python3 -m pip install -e .[dev,doc]
86
+ # Set up the git hook scripts
87
+ $ pre-commit install
88
+ # Create your feature/fix
89
+ # Create tests for your changes
90
+ $ python -m unittest
91
+ # Push you feature/fix on Github
92
+ $ git add [file(s)]
93
+ $ git commit -m "[descriptive message]"
94
+ $ git push origin [branch-name]
95
+ # Open a pull request
96
+ ```
97
+
98
+ ### Install the package locally
99
+
100
+ ```bash
101
+ $ pip install -e .
102
+ ```
103
+
104
+ ## Documentation
105
+
106
+ ### Client usage
107
+
108
+ To learn about how to use the OpenAEV Python client and read some examples and cases, refer to [the client documentation](https://openaev-client-for-python.readthedocs.io/en/latest/client_usage/getting_started.html).
109
+
110
+ ### API reference
111
+
112
+ To learn about the methods available for executing queries and retrieving their answers, refer to [the client API Reference](https://openaev-client-for-python.readthedocs.io/en/latest/pyoaev/pyoaev.html).
113
+
114
+ ## Tests
115
+
116
+ The standard `unittest` library is used for running the tests.
117
+
118
+ ```bash
119
+ $ python -m unittest
120
+ ```
121
+
122
+ ## Code Coverage
123
+
124
+ To run the tests and generate a code coverage report:
125
+
126
+ ```bash
127
+ pytest --cov=. tests/
128
+ ```
129
+
130
+ ## About
131
+
132
+ OpenAEV is a product designed and developed by the company [Filigran](https://filigran.io).
133
+
134
+ <a href="https://filigran.io" alt="Filigran"><img src="https://github.com/OpenAEV-Platform/openaev/raw/master/.github/img/logo_filigran.png" width="300" /></a>
@@ -0,0 +1,72 @@
1
+ docs/conf.py,sha256=_030QD2TV3WgBr8WUpx8HMSSj7NMJMsRFWN7MZ06zI0,2159
2
+ pyoaev/__init__.py,sha256=0fl-Jgp4pcrojfk_FCZ-BIn0KFdGvin9pg3nQ14_uZg,641
3
+ pyoaev/_version.py,sha256=8iMS-Y9389dC7HtReHJGNnoDgyfNbA3m-V32pCvIaz8,185
4
+ pyoaev/base.py,sha256=nJh2Hg9Aw4UcjMrp0nklG5cqHHOKmMPJBRwV0UUNZO0,10756
5
+ pyoaev/client.py,sha256=IEno-WRNQcqLyA_ex7SbnniB8OMuWOIsNZ1gJ7fb63M,22342
6
+ pyoaev/exceptions.py,sha256=3LIn8wmgPlBuxqO-naOPaEi4-bs05IjFILW-J4n594M,7916
7
+ pyoaev/helpers.py,sha256=n4Z5Eq5kiZg0nA-K8cu35j_0vWRHWXBmUCrX5YCx2Aw,17185
8
+ pyoaev/mixins.py,sha256=inqfNP5l4vmc_npA3w2j3DCUI5iJBvqZdnPeXEnLBUo,7506
9
+ pyoaev/utils.py,sha256=Hph7ly0PVyEadkRJI_bRbXF-iwkb_XjFeglAei-myDA,6617
10
+ pyoaev/apis/__init__.py,sha256=9U8sfFKoxncUtkNpz7qHrq6u-kKynIiybQR2MPptQHc,874
11
+ pyoaev/apis/attack_pattern.py,sha256=Qq0rz9C8xPZEde4B73O8tXwDNuymLv3pVPMVaHZC3Kc,772
12
+ pyoaev/apis/collector.py,sha256=BW5gtwPuqFbmQ5sxFa2xJ50Rtab9IN6N8Z4SmaOsBLo,841
13
+ pyoaev/apis/cve.py,sha256=aFubPmfY0MG__I-sZhM2WqOqL6BqRH0ZgkToKlUgjEw,471
14
+ pyoaev/apis/document.py,sha256=KTwV7oMMsIy-MhY05GTORlRlBlOxxW4wEdMwPChwYtQ,851
15
+ pyoaev/apis/endpoint.py,sha256=2gCCjDE9Hd2bDjl_1__bUCn3WSOm8yMGVLZMlm29eTE,1113
16
+ pyoaev/apis/inject.py,sha256=cdSFXe-Gd6RZfTYCJ4ZnH0MDk5YfesMJjZIH9LQ98Ag,890
17
+ pyoaev/apis/inject_expectation_trace.py,sha256=QeYbleKOky7Cvt-oIN9vMCgOYM-LwlmzgoTVa3X64Ms,1101
18
+ pyoaev/apis/injector.py,sha256=tFcu2kcmlLpQUyG5CeNE3m5j7PLbao0paiY-MDFyuNo,722
19
+ pyoaev/apis/injector_contract.py,sha256=Jc-sbuo_P9oVIUDNeoLkoa7Eehd3NzEqDxc7J16LH-g,1793
20
+ pyoaev/apis/kill_chain_phase.py,sha256=vlv4u_6UnCH4eojHyWAG65xlgqka11Y8dPVNieLFpuY,635
21
+ pyoaev/apis/me.py,sha256=Fxlsnn8MuQva2910XhipX95V3GjiIQObZgj0DA5h9dA,397
22
+ pyoaev/apis/organization.py,sha256=TCR1iiGnDVCsGm0zbVRcC3ARv7qzTukkLP1157CmOfI,263
23
+ pyoaev/apis/payload.py,sha256=8XiZpX87VlcC2paM_XfhbIcJfDJdTcbDISw2Jkt5LFs,822
24
+ pyoaev/apis/security_platform.py,sha256=u2UN5yKHiHYNHGKwbai4S9WYDfASqZ0BNkqI2VBx2K8,990
25
+ pyoaev/apis/tag.py,sha256=r_UpNsBlVtzMqbfLxFtU5RDihlQVHo2qz8X5B_uhGhg,492
26
+ pyoaev/apis/team.py,sha256=PZ1D4WHR6MLhAzClrFOaRuzpRq5IZNx3yCHipM-A6f4,788
27
+ pyoaev/apis/user.py,sha256=Fr821Cu3V9B1U9p4oNKZ5u2feHeYe5669Oc55E3G_Og,893
28
+ pyoaev/apis/inject_expectation/__init__.py,sha256=jPlnzxfT31MhmUgEvR4pBAuyG_ciX23-wMKYT5qX5Dc,53
29
+ pyoaev/apis/inject_expectation/inject_expectation.py,sha256=if-OD0uVERQKPExi9mN2CBjlbeqh6T3tP49A4-9nqJU,4217
30
+ pyoaev/apis/inject_expectation/model/__init__.py,sha256=CloFGul64uYDxEdKJr6eZzlFr1eVPb95cqTnRPr0AEU,191
31
+ pyoaev/apis/inject_expectation/model/expectation.py,sha256=Uq0pIdLpXJABX2WNwi3Vj9b4Ygs0D30Xrr2SR0vzdpA,6323
32
+ pyoaev/apis/inputs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ pyoaev/apis/inputs/search.py,sha256=DqB7HEtqZg1aS1PwuaC-MatU-vcH0hanNtt6eZMXjrI,2204
34
+ pyoaev/backends/__init__.py,sha256=Y3tsbazJZB7Fme52fCGGprn3-UdQQjalIJ1hansjvzw,272
35
+ pyoaev/backends/backend.py,sha256=4U2Ver8rQd49VqRjb-94fmUJxOeqrBblwpFeHXUCFeI,4328
36
+ pyoaev/backends/protocol.py,sha256=m5qSz1o3i0H4XJCWnqx0wIFilOIU9cKxzFsYxLL6Big,842
37
+ pyoaev/configuration/__init__.py,sha256=cifJWZdzsvv6n9AjGGWTiOOQf_-FAak0QIzSb2L7d78,70
38
+ pyoaev/configuration/configuration.py,sha256=i4DaCfCgKSz5DiQPCUIcw6N-BO8rYoKbWZcZhcbDY0Q,6905
39
+ pyoaev/configuration/sources.py,sha256=09B4X3nUvlRIv1fcAZGZBP-ScV-AOyVrYuLGzMT1zWg,1459
40
+ pyoaev/contracts/__init__.py,sha256=vt5JcjJquIEBt1Bwr1FfvTL9gJQHAO46eYPRG65ehzk,103
41
+ pyoaev/contracts/contract_builder.py,sha256=nZ8E2TcvYq6f_diS4pjshdnldZNmljETnAYAS5G-oW8,1305
42
+ pyoaev/contracts/contract_config.py,sha256=uthRpbvrNYJHVGj_ChSOm8C-aSKtn34gyrCeY_aILjA,7824
43
+ pyoaev/contracts/contract_utils.py,sha256=htaXoG9ndBOYhFsoBXrGludPU79d4aUOejc-I0SSiPU,451
44
+ pyoaev/contracts/variable_helper.py,sha256=2YKCzs_qco0JBRhGYuiMh_aIB6sFJIIzj_CRkx-QLLo,4208
45
+ pyoaev/daemons/__init__.py,sha256=IdR-AYxEjpMIst0Y1oqsmKw4-mc5RSOmGtpxVM4cLHY,127
46
+ pyoaev/daemons/base_daemon.py,sha256=1EssjncVGO57TridSHZ4OBClgi6pYwjIAYSlDrrjxQg,5034
47
+ pyoaev/daemons/collector_daemon.py,sha256=DX9rhHYIEcJq_8vLSWzaWyCgOofWpZ0-YNQ3FviIue8,3783
48
+ pyoaev/signatures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ pyoaev/signatures/signature_match.py,sha256=EclhdT2QSf19rr76IxhcISgqXCSU9bvJHQ2Bt7Z-Uek,485
50
+ pyoaev/signatures/signature_type.py,sha256=E-tn_Fhftssf7v-rQy0EbPvsUAvCTTIrlG7LbOsouDo,1684
51
+ pyoaev/signatures/types.py,sha256=uDA_8u2t1qdHQdue8hiw2sO59yahbfL2uDKUoQhktx0,576
52
+ pyoaev-1.18.20.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
53
+ scripts/release.py,sha256=2ZBVqpGqajYNLkDOiVAtRf3DvDe97umErVAgEav2EP4,4387
54
+ test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ test/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
+ test/apis/expectation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ test/apis/expectation/test_expectation.py,sha256=BNdZpIjwsiuOCHsdCf0cGcf7Ck-tQ49yxvTXbS6n89w,11500
58
+ test/apis/injector_contract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
+ test/apis/injector_contract/test_injector_contract.py,sha256=d_EPy8bMVzNGoEL2xlsiZE_6Kz0lEMfVJp9t8Ci9BrY,1555
60
+ test/configuration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ test/configuration/test_configuration.py,sha256=soJblSpiZ5HenfQchVy8k93i8t3LUDjd2yfl-YFacow,8132
62
+ test/configuration/test_sources.py,sha256=PbViObmq4I1v0GDyKu8cv-q5UouMj-CErSugii85a70,2261
63
+ test/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ test/daemons/test_base_daemon.py,sha256=DWOHIBMSFEz02Jxz5VCtNgS8OAPlJK0EmQT-ucmWUn8,3225
65
+ test/daemons/test_collector_daemon.py,sha256=Z2zzpzj1TVQuLXJY1cKptPihv0AGumraI4bPtwXnaTM,1288
66
+ test/signatures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
+ test/signatures/test_signature_match.py,sha256=2iT5M_EnUE2OKE8xe_Jl-Le6gsuQlW3VMAd1iaFGt04,793
68
+ test/signatures/test_signature_type.py,sha256=EznFiGxzKyIiydpB9M6Ytj5P_5emgK3AMQ6lIbvxmZA,2413
69
+ pyoaev-1.18.20.dist-info/METADATA,sha256=1I6gxH-_tZsOqiCm2kUwzvITJG013eSBa869_QU-DnE,5155
70
+ pyoaev-1.18.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
71
+ pyoaev-1.18.20.dist-info/top_level.txt,sha256=je2hy1nZbVjTQzH55BQC6Lmduwyu9FOowXzx7NH7Ceg,25
72
+ pyoaev-1.18.20.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+