pyoaev 1.18.20__py3-none-any.whl → 2.0.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.
pyoaev/__init__.py CHANGED
@@ -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__,
pyoaev/_version.py CHANGED
@@ -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"
pyoaev/apis/endpoint.py CHANGED
@@ -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>
@@ -1,6 +1,6 @@
1
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
2
+ pyoaev/__init__.py,sha256=UHkFjk3BeBJEUxei_6ksCSh9p7ZAYgZhdyIYRunXKic,639
3
+ pyoaev/_version.py,sha256=47x2aI-zSoUWYmxKkU0eF-7DS1qT_BKY9q8n1San-Cc,183
4
4
  pyoaev/base.py,sha256=nJh2Hg9Aw4UcjMrp0nklG5cqHHOKmMPJBRwV0UUNZO0,10756
5
5
  pyoaev/client.py,sha256=IEno-WRNQcqLyA_ex7SbnniB8OMuWOIsNZ1gJ7fb63M,22342
6
6
  pyoaev/exceptions.py,sha256=3LIn8wmgPlBuxqO-naOPaEi4-bs05IjFILW-J4n594M,7916
@@ -12,7 +12,7 @@ pyoaev/apis/attack_pattern.py,sha256=Qq0rz9C8xPZEde4B73O8tXwDNuymLv3pVPMVaHZC3Kc
12
12
  pyoaev/apis/collector.py,sha256=BW5gtwPuqFbmQ5sxFa2xJ50Rtab9IN6N8Z4SmaOsBLo,841
13
13
  pyoaev/apis/cve.py,sha256=aFubPmfY0MG__I-sZhM2WqOqL6BqRH0ZgkToKlUgjEw,471
14
14
  pyoaev/apis/document.py,sha256=KTwV7oMMsIy-MhY05GTORlRlBlOxxW4wEdMwPChwYtQ,851
15
- pyoaev/apis/endpoint.py,sha256=2gCCjDE9Hd2bDjl_1__bUCn3WSOm8yMGVLZMlm29eTE,1113
15
+ pyoaev/apis/endpoint.py,sha256=JWnWyGumxPR2edeqkjqHy3wntG-vEWTEZSrUQ867j2U,1470
16
16
  pyoaev/apis/inject.py,sha256=cdSFXe-Gd6RZfTYCJ4ZnH0MDk5YfesMJjZIH9LQ98Ag,890
17
17
  pyoaev/apis/inject_expectation_trace.py,sha256=QeYbleKOky7Cvt-oIN9vMCgOYM-LwlmzgoTVa3X64Ms,1101
18
18
  pyoaev/apis/injector.py,sha256=tFcu2kcmlLpQUyG5CeNE3m5j7PLbao0paiY-MDFyuNo,722
@@ -26,7 +26,7 @@ pyoaev/apis/tag.py,sha256=r_UpNsBlVtzMqbfLxFtU5RDihlQVHo2qz8X5B_uhGhg,492
26
26
  pyoaev/apis/team.py,sha256=PZ1D4WHR6MLhAzClrFOaRuzpRq5IZNx3yCHipM-A6f4,788
27
27
  pyoaev/apis/user.py,sha256=Fr821Cu3V9B1U9p4oNKZ5u2feHeYe5669Oc55E3G_Og,893
28
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
29
+ pyoaev/apis/inject_expectation/inject_expectation.py,sha256=eT3NNIMS10zZIEcBQcTG2nWMBXGYd4AInpXqL4GMUUk,4615
30
30
  pyoaev/apis/inject_expectation/model/__init__.py,sha256=CloFGul64uYDxEdKJr6eZzlFr1eVPb95cqTnRPr0AEU,191
31
31
  pyoaev/apis/inject_expectation/model/expectation.py,sha256=Uq0pIdLpXJABX2WNwi3Vj9b4Ygs0D30Xrr2SR0vzdpA,6323
32
32
  pyoaev/apis/inputs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -39,7 +39,7 @@ pyoaev/configuration/configuration.py,sha256=i4DaCfCgKSz5DiQPCUIcw6N-BO8rYoKbWZc
39
39
  pyoaev/configuration/sources.py,sha256=09B4X3nUvlRIv1fcAZGZBP-ScV-AOyVrYuLGzMT1zWg,1459
40
40
  pyoaev/contracts/__init__.py,sha256=vt5JcjJquIEBt1Bwr1FfvTL9gJQHAO46eYPRG65ehzk,103
41
41
  pyoaev/contracts/contract_builder.py,sha256=nZ8E2TcvYq6f_diS4pjshdnldZNmljETnAYAS5G-oW8,1305
42
- pyoaev/contracts/contract_config.py,sha256=uthRpbvrNYJHVGj_ChSOm8C-aSKtn34gyrCeY_aILjA,7824
42
+ pyoaev/contracts/contract_config.py,sha256=vi6_5dcOf-Z1TKV69K8Z9LIbqe4beHExiQb8dVO76V8,8071
43
43
  pyoaev/contracts/contract_utils.py,sha256=htaXoG9ndBOYhFsoBXrGludPU79d4aUOejc-I0SSiPU,451
44
44
  pyoaev/contracts/variable_helper.py,sha256=2YKCzs_qco0JBRhGYuiMh_aIB6sFJIIzj_CRkx-QLLo,4208
45
45
  pyoaev/daemons/__init__.py,sha256=IdR-AYxEjpMIst0Y1oqsmKw4-mc5RSOmGtpxVM4cLHY,127
@@ -49,10 +49,12 @@ pyoaev/signatures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
49
49
  pyoaev/signatures/signature_match.py,sha256=EclhdT2QSf19rr76IxhcISgqXCSU9bvJHQ2Bt7Z-Uek,485
50
50
  pyoaev/signatures/signature_type.py,sha256=E-tn_Fhftssf7v-rQy0EbPvsUAvCTTIrlG7LbOsouDo,1684
51
51
  pyoaev/signatures/types.py,sha256=uDA_8u2t1qdHQdue8hiw2sO59yahbfL2uDKUoQhktx0,576
52
- pyoaev-1.18.20.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
52
+ pyoaev-2.0.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
53
53
  scripts/release.py,sha256=2ZBVqpGqajYNLkDOiVAtRf3DvDe97umErVAgEav2EP4,4387
54
54
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  test/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
+ test/apis/endpoint/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ test/apis/endpoint/test_endpoint.py,sha256=79XJk5T6cpp6y0zdxjD7ZzKogbq9QVMm8jsWCjr474o,1566
56
58
  test/apis/expectation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
59
  test/apis/expectation/test_expectation.py,sha256=BNdZpIjwsiuOCHsdCf0cGcf7Ck-tQ49yxvTXbS6n89w,11500
58
60
  test/apis/injector_contract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -66,7 +68,7 @@ test/daemons/test_collector_daemon.py,sha256=Z2zzpzj1TVQuLXJY1cKptPihv0AGumraI4b
66
68
  test/signatures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
69
  test/signatures/test_signature_match.py,sha256=2iT5M_EnUE2OKE8xe_Jl-Le6gsuQlW3VMAd1iaFGt04,793
68
70
  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,,
71
+ pyoaev-2.0.1.dist-info/METADATA,sha256=qTJoHyi909P_d4cFc-YONxGvYiPmtv1WN0V97aqe5HQ,5153
72
+ pyoaev-2.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
73
+ pyoaev-2.0.1.dist-info/top_level.txt,sha256=je2hy1nZbVjTQzH55BQC6Lmduwyu9FOowXzx7NH7Ceg,25
74
+ pyoaev-2.0.1.dist-info/RECORD,,
File without changes
@@ -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()