pyoaev 1.18.20__tar.gz → 2.0.1__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.
Files changed (79) hide show
  1. {pyoaev-1.18.20/pyoaev.egg-info → pyoaev-2.0.1}/PKG-INFO +1 -1
  2. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/__init__.py +1 -1
  3. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/_version.py +1 -1
  4. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/endpoint.py +9 -0
  5. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inject_expectation/inject_expectation.py +7 -1
  6. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/contracts/contract_config.py +7 -0
  7. {pyoaev-1.18.20 → pyoaev-2.0.1/pyoaev.egg-info}/PKG-INFO +1 -1
  8. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev.egg-info/SOURCES.txt +2 -0
  9. pyoaev-2.0.1/test/apis/endpoint/test_endpoint.py +57 -0
  10. pyoaev-2.0.1/test/signatures/__init__.py +0 -0
  11. {pyoaev-1.18.20 → pyoaev-2.0.1}/LICENSE +0 -0
  12. {pyoaev-1.18.20 → pyoaev-2.0.1}/README.md +0 -0
  13. {pyoaev-1.18.20 → pyoaev-2.0.1}/docs/conf.py +0 -0
  14. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/__init__.py +0 -0
  15. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/attack_pattern.py +0 -0
  16. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/collector.py +0 -0
  17. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/cve.py +0 -0
  18. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/document.py +0 -0
  19. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inject.py +0 -0
  20. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inject_expectation/__init__.py +0 -0
  21. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inject_expectation/model/__init__.py +0 -0
  22. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inject_expectation/model/expectation.py +0 -0
  23. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inject_expectation_trace.py +0 -0
  24. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/injector.py +0 -0
  25. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/injector_contract.py +0 -0
  26. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inputs/__init__.py +0 -0
  27. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/inputs/search.py +0 -0
  28. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/kill_chain_phase.py +0 -0
  29. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/me.py +0 -0
  30. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/organization.py +0 -0
  31. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/payload.py +0 -0
  32. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/security_platform.py +0 -0
  33. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/tag.py +0 -0
  34. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/team.py +0 -0
  35. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/apis/user.py +0 -0
  36. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/backends/__init__.py +0 -0
  37. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/backends/backend.py +0 -0
  38. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/backends/protocol.py +0 -0
  39. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/base.py +0 -0
  40. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/client.py +0 -0
  41. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/configuration/__init__.py +0 -0
  42. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/configuration/configuration.py +0 -0
  43. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/configuration/sources.py +0 -0
  44. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/contracts/__init__.py +0 -0
  45. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/contracts/contract_builder.py +0 -0
  46. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/contracts/contract_utils.py +0 -0
  47. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/contracts/variable_helper.py +0 -0
  48. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/daemons/__init__.py +0 -0
  49. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/daemons/base_daemon.py +0 -0
  50. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/daemons/collector_daemon.py +0 -0
  51. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/exceptions.py +0 -0
  52. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/helpers.py +0 -0
  53. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/mixins.py +0 -0
  54. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/signatures/__init__.py +0 -0
  55. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/signatures/signature_match.py +0 -0
  56. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/signatures/signature_type.py +0 -0
  57. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/signatures/types.py +0 -0
  58. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev/utils.py +0 -0
  59. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev.egg-info/dependency_links.txt +0 -0
  60. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev.egg-info/requires.txt +0 -0
  61. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyoaev.egg-info/top_level.txt +0 -0
  62. {pyoaev-1.18.20 → pyoaev-2.0.1}/pyproject.toml +0 -0
  63. {pyoaev-1.18.20 → pyoaev-2.0.1}/scripts/release.py +0 -0
  64. {pyoaev-1.18.20 → pyoaev-2.0.1}/setup.cfg +0 -0
  65. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/__init__.py +0 -0
  66. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/apis/__init__.py +0 -0
  67. {pyoaev-1.18.20/test/apis/expectation → pyoaev-2.0.1/test/apis/endpoint}/__init__.py +0 -0
  68. {pyoaev-1.18.20/test/apis/injector_contract → pyoaev-2.0.1/test/apis/expectation}/__init__.py +0 -0
  69. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/apis/expectation/test_expectation.py +0 -0
  70. {pyoaev-1.18.20/test/configuration → pyoaev-2.0.1/test/apis/injector_contract}/__init__.py +0 -0
  71. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/apis/injector_contract/test_injector_contract.py +0 -0
  72. {pyoaev-1.18.20/test/daemons → pyoaev-2.0.1/test/configuration}/__init__.py +0 -0
  73. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/configuration/test_configuration.py +0 -0
  74. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/configuration/test_sources.py +0 -0
  75. {pyoaev-1.18.20/test/signatures → pyoaev-2.0.1/test/daemons}/__init__.py +0 -0
  76. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/daemons/test_base_daemon.py +0 -0
  77. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/daemons/test_collector_daemon.py +0 -0
  78. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/signatures/test_signature_match.py +0 -0
  79. {pyoaev-1.18.20 → pyoaev-2.0.1}/test/signatures/test_signature_type.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyoaev
3
- Version: 1.18.20
3
+ Version: 2.0.1
4
4
  Summary: Python API client for OpenAEV.
5
5
  Author-email: Filigran <contact@filigran.io>
6
6
  Maintainer-email: Filigran <contact@filigran.io>
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- __version__ = "1.18.20"
2
+ __version__ = "2.0.1"
3
3
 
4
4
  from pyoaev._version import ( # noqa: F401
5
5
  __author__,
@@ -3,4 +3,4 @@ __copyright__ = "Copyright 2025 Filigran"
3
3
  __email__ = "contact@filigran.io"
4
4
  __license__ = "Apache 2.0"
5
5
  __title__ = "python-openaev"
6
- __version__ = "1.18.20"
6
+ __version__ = "2.0.1"
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Dict
2
2
 
3
3
  from pyoaev import exceptions as exc
4
+ from pyoaev.apis.inputs.search import SearchPaginationInput
4
5
  from pyoaev.base import RESTManager, RESTObject
5
6
  from pyoaev.utils import RequiredOptional
6
7
 
@@ -36,3 +37,11 @@ class EndpointManager(RESTManager):
36
37
  path = f"{self.path}/agentless/upsert"
37
38
  result = self.openaev.http_post(path, post_data=endpoint, **kwargs)
38
39
  return result
40
+
41
+ @exc.on_http_error(exc.OpenAEVUpdateError)
42
+ def searchTargets(
43
+ self, input: SearchPaginationInput, **kwargs: Any
44
+ ) -> Dict[str, Any]:
45
+ path = f"{self.path}/targets"
46
+ result = self.openaev.http_post(path, post_data=input.to_dict(), **kwargs)
47
+ return result
@@ -28,7 +28,13 @@ class InjectExpectationManager(ListMixin, UpdateMixin, RESTManager):
28
28
  result = self.openaev.http_get(
29
29
  path,
30
30
  query_data=(
31
- {"expiration_time": expiration_time} if expiration_time else None
31
+ {"expiration_time": expiration_time}
32
+ if expiration_time
33
+ else {
34
+ "expiration_time": 360
35
+ } # 360 minutes (6 hours) - corresponds to the expiration time configured in the Expectations Expiration Manager.
36
+ # Expectations older than this duration will be automatically expired to prevent
37
+ # processing outdated data, particularly important when launching new collectors.
32
38
  ),
33
39
  **kwargs,
34
40
  )
@@ -32,6 +32,11 @@ class ContractFieldType(str, Enum):
32
32
  Payload: str = "payload"
33
33
 
34
34
 
35
+ class ContractFieldKey(str, Enum):
36
+ Asset: str = "assets"
37
+ AssetGroup: str = "asset_groups"
38
+
39
+
35
40
  class ContractOutputType(str, Enum):
36
41
  Text: str = "text"
37
42
  Number: str = "number"
@@ -270,6 +275,7 @@ class ContractSelect(ContractCardinalityElement):
270
275
 
271
276
  @dataclass
272
277
  class ContractAsset(ContractCardinalityElement):
278
+ key: str = field(default=ContractFieldKey.Asset.value, init=False)
273
279
 
274
280
  @property
275
281
  def get_type(self) -> str:
@@ -278,6 +284,7 @@ class ContractAsset(ContractCardinalityElement):
278
284
 
279
285
  @dataclass
280
286
  class ContractAssetGroup(ContractCardinalityElement):
287
+ key: str = field(default=ContractFieldKey.AssetGroup.value, init=False)
281
288
 
282
289
  @property
283
290
  def get_type(self) -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyoaev
3
- Version: 1.18.20
3
+ Version: 2.0.1
4
4
  Summary: Python API client for OpenAEV.
5
5
  Author-email: Filigran <contact@filigran.io>
6
6
  Maintainer-email: Filigran <contact@filigran.io>
@@ -60,6 +60,8 @@ pyoaev/signatures/types.py
60
60
  scripts/release.py
61
61
  test/__init__.py
62
62
  test/apis/__init__.py
63
+ test/apis/endpoint/__init__.py
64
+ test/apis/endpoint/test_endpoint.py
63
65
  test/apis/expectation/__init__.py
64
66
  test/apis/expectation/test_expectation.py
65
67
  test/apis/injector_contract/__init__.py
@@ -0,0 +1,57 @@
1
+ from unittest import TestCase, main, mock
2
+ from unittest.mock import ANY
3
+
4
+ from pyoaev import OpenAEV
5
+ from pyoaev.apis.inputs.search import Filter, FilterGroup, SearchPaginationInput
6
+
7
+
8
+ def mock_response(**kwargs):
9
+ class MockResponse:
10
+ def __init__(self, json_data, status_code):
11
+ self.json_data = json_data
12
+ self.status_code = status_code
13
+ self.history = None
14
+ self.content = None
15
+ self.headers = {"Content-Type": "application/json"}
16
+
17
+ def json(self):
18
+ return self.json_data
19
+
20
+ return MockResponse(None, 200)
21
+
22
+
23
+ class TestInjectorContract(TestCase):
24
+ @mock.patch("requests.Session.request", side_effect=mock_response)
25
+ def test_search_input_correctly_serialised(self, mock_request):
26
+ api_client = OpenAEV("url", "token")
27
+
28
+ search_input = SearchPaginationInput(
29
+ 0,
30
+ 20,
31
+ FilterGroup(
32
+ "or",
33
+ [Filter("targets", "and", "eq", ["target_1", "target_2", "target_3"])],
34
+ ),
35
+ None,
36
+ None,
37
+ )
38
+
39
+ expected_json = search_input.to_dict()
40
+ api_client.endpoint.searchTargets(search_input)
41
+
42
+ mock_request.assert_called_once_with(
43
+ method="post",
44
+ url="url/api/endpoints/targets",
45
+ params={},
46
+ data=None,
47
+ timeout=None,
48
+ stream=False,
49
+ verify=True,
50
+ json=expected_json,
51
+ headers=ANY,
52
+ auth=ANY,
53
+ )
54
+
55
+
56
+ if __name__ == "__main__":
57
+ main()
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