pangea-sdk 6.2.0b1__tar.gz → 6.2.0b2__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.
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/PKG-INFO +6 -6
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/README.md +2 -2
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/__init__.py +9 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/__init__.py +1 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/file_uploader.py +4 -2
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/request.py +51 -21
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/__init__.py +2 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/ai_guard.py +91 -2
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/audit.py +14 -8
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/authn.py +33 -23
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/authz.py +6 -6
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/base.py +4 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/file_scan.py +8 -2
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/intel.py +6 -2
- pangea_sdk-6.2.0b2/pangea/asyncio/services/prompt_guard.py +194 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/redact.py +7 -3
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/sanitize.py +5 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/share.py +5 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/vault.py +19 -15
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/audit_logger.py +3 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/deep_verify.py +13 -13
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/deprecated.py +1 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/dump_audit.py +2 -3
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/exceptions.py +8 -5
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/file_uploader.py +4 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/request.py +58 -41
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/response.py +15 -12
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/__init__.py +2 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/ai_guard.py +497 -16
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/audit/audit.py +15 -13
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/audit/models.py +4 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/audit/signing.py +1 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/audit/util.py +10 -10
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/authn/authn.py +33 -23
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/authn/models.py +3 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/authz.py +10 -6
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/base.py +5 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/embargo.py +6 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/file_scan.py +8 -2
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/intel.py +4 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/management.py +8 -8
- pangea_sdk-6.2.0b2/pangea/services/prompt_guard.py +309 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/redact.py +7 -3
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/sanitize.py +5 -1
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/share/share.py +13 -7
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/vault/models/asymmetric.py +4 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/vault/models/common.py +4 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/vault/models/symmetric.py +4 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/vault/vault.py +17 -19
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/tools.py +13 -9
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/utils.py +3 -5
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/verify_audit.py +23 -27
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pyproject.toml +16 -17
- pangea_sdk-6.2.0b1/pangea/asyncio/services/prompt_guard.py +0 -84
- pangea_sdk-6.2.0b1/pangea/services/prompt_guard.py +0 -118
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/embargo.py +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/asyncio/services/management.py +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/config.py +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/crypto/rsa.py +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/py.typed +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/audit/exceptions.py +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/share/file_format.py +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/vault/models/keys.py +0 -0
- {pangea_sdk-6.2.0b1 → pangea_sdk-6.2.0b2}/pangea/services/vault/models/secret.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: pangea-sdk
|
3
|
-
Version: 6.2.
|
3
|
+
Version: 6.2.0b2
|
4
4
|
Summary: Pangea API SDK
|
5
5
|
License: MIT
|
6
6
|
Keywords: Pangea,SDK,Audit
|
@@ -9,11 +9,11 @@ Author-email: glenn.gallien@pangea.cloud
|
|
9
9
|
Requires-Python: >=3.9.2,<4.0.0
|
10
10
|
Classifier: Topic :: Software Development
|
11
11
|
Classifier: Topic :: Software Development :: Libraries
|
12
|
-
Requires-Dist: aiohttp (>=3.11.
|
13
|
-
Requires-Dist: cryptography (>=
|
12
|
+
Requires-Dist: aiohttp (>=3.11.18,<4.0.0)
|
13
|
+
Requires-Dist: cryptography (>=45.0.2,<46.0.0)
|
14
14
|
Requires-Dist: deprecated (>=1.2.18,<2.0.0)
|
15
15
|
Requires-Dist: google-crc32c (>=1.7.1,<2.0.0)
|
16
|
-
Requires-Dist: pydantic (>=2.11.
|
16
|
+
Requires-Dist: pydantic (>=2.11.4,<3.0.0)
|
17
17
|
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
18
18
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
19
19
|
Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
|
@@ -63,13 +63,13 @@ the same compatibility guarantees as stable releases.
|
|
63
63
|
Via pip:
|
64
64
|
|
65
65
|
```bash
|
66
|
-
$ pip3 install pangea-sdk==6.2.
|
66
|
+
$ pip3 install pangea-sdk==6.2.0b2
|
67
67
|
```
|
68
68
|
|
69
69
|
Via poetry:
|
70
70
|
|
71
71
|
```bash
|
72
|
-
$ poetry add pangea-sdk==6.2.
|
72
|
+
$ poetry add pangea-sdk==6.2.0b2
|
73
73
|
```
|
74
74
|
|
75
75
|
## Usage
|
@@ -40,13 +40,13 @@ the same compatibility guarantees as stable releases.
|
|
40
40
|
Via pip:
|
41
41
|
|
42
42
|
```bash
|
43
|
-
$ pip3 install pangea-sdk==6.2.
|
43
|
+
$ pip3 install pangea-sdk==6.2.0b2
|
44
44
|
```
|
45
45
|
|
46
46
|
Via poetry:
|
47
47
|
|
48
48
|
```bash
|
49
|
-
$ poetry add pangea-sdk==6.2.
|
49
|
+
$ poetry add pangea-sdk==6.2.0b2
|
50
50
|
```
|
51
51
|
|
52
52
|
## Usage
|
@@ -1,7 +1,15 @@
|
|
1
|
-
__version__ = "6.2.
|
1
|
+
__version__ = "6.2.0beta2"
|
2
2
|
|
3
3
|
from pangea.asyncio.request import PangeaRequestAsync
|
4
4
|
from pangea.config import PangeaConfig
|
5
5
|
from pangea.file_uploader import FileUploader
|
6
6
|
from pangea.request import PangeaRequest
|
7
7
|
from pangea.response import PangeaResponse
|
8
|
+
|
9
|
+
__all__ = (
|
10
|
+
"FileUploader",
|
11
|
+
"PangeaConfig",
|
12
|
+
"PangeaRequest",
|
13
|
+
"PangeaRequestAsync",
|
14
|
+
"PangeaResponse",
|
15
|
+
)
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
from __future__ import annotations
|
5
|
+
|
3
6
|
import io
|
4
7
|
import logging
|
5
|
-
from typing import Dict, Optional
|
6
8
|
|
7
9
|
from pangea.asyncio.request import PangeaRequestAsync
|
8
10
|
from pangea.request import PangeaConfig
|
@@ -24,7 +26,7 @@ class FileUploaderAsync:
|
|
24
26
|
url: str,
|
25
27
|
file: io.BufferedReader,
|
26
28
|
transfer_method: TransferMethod = TransferMethod.PUT_URL,
|
27
|
-
file_details:
|
29
|
+
file_details: dict | None = None,
|
28
30
|
) -> None:
|
29
31
|
if transfer_method == TransferMethod.PUT_URL:
|
30
32
|
files = [("file", ("filename", file, "application/octet-stream"))]
|
@@ -1,24 +1,39 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
# TODO: Modernize.
|
5
|
+
# ruff: noqa: UP006, UP035
|
6
|
+
|
3
7
|
from __future__ import annotations
|
4
8
|
|
5
9
|
import asyncio
|
6
10
|
import json
|
7
11
|
import time
|
8
12
|
from collections.abc import Iterable, Mapping
|
9
|
-
from typing import Dict, List,
|
13
|
+
from typing import Dict, List, Optional, Sequence, Tuple, Type, Union, cast, overload
|
10
14
|
|
11
15
|
import aiohttp
|
12
16
|
from aiohttp import FormData
|
13
17
|
from pydantic import BaseModel, TypeAdapter
|
14
18
|
from pydantic_core import to_jsonable_python
|
15
|
-
from typing_extensions import Any, TypeVar
|
19
|
+
from typing_extensions import Any, Literal, TypeAlias, TypeVar, override
|
16
20
|
|
17
21
|
import pangea.exceptions as pe
|
18
22
|
from pangea.request import MultipartResponse, PangeaRequestBase
|
19
23
|
from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
|
20
24
|
from pangea.utils import default_encoder
|
21
25
|
|
26
|
+
_FileName: TypeAlias = Union[str, None]
|
27
|
+
_FileContent: TypeAlias = Union[str, bytes]
|
28
|
+
_FileContentType: TypeAlias = str
|
29
|
+
_FileCustomHeaders: TypeAlias = Mapping[str, str]
|
30
|
+
_FileSpecTuple2: TypeAlias = tuple[_FileName, _FileContent]
|
31
|
+
_FileSpecTuple3: TypeAlias = tuple[_FileName, _FileContent, _FileContentType]
|
32
|
+
_FileSpecTuple4: TypeAlias = tuple[_FileName, _FileContent, _FileContentType, _FileCustomHeaders]
|
33
|
+
_FileSpec: TypeAlias = Union[_FileContent, _FileSpecTuple2, _FileSpecTuple3, _FileSpecTuple4]
|
34
|
+
_Files: TypeAlias = Union[Mapping[str, _FileSpec], Iterable[tuple[str, _FileSpec]]]
|
35
|
+
|
36
|
+
|
22
37
|
TResult = TypeVar("TResult", bound=PangeaResponseResult)
|
23
38
|
|
24
39
|
|
@@ -53,7 +68,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
53
68
|
self,
|
54
69
|
endpoint: str,
|
55
70
|
result_class: Type[TResult],
|
56
|
-
data: str | BaseModel |
|
71
|
+
data: str | BaseModel | Mapping[str, Any] | None = None,
|
57
72
|
files: Optional[List[Tuple]] = None,
|
58
73
|
poll_result: bool = True,
|
59
74
|
url: Optional[str] = None,
|
@@ -77,7 +92,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
77
92
|
self,
|
78
93
|
endpoint: str,
|
79
94
|
result_class: Type[TResult],
|
80
|
-
data: str | BaseModel |
|
95
|
+
data: str | BaseModel | Mapping[str, Any] | None = None,
|
81
96
|
files: Optional[List[Tuple]] = None,
|
82
97
|
poll_result: bool = True,
|
83
98
|
url: Optional[str] = None,
|
@@ -96,7 +111,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
96
111
|
self,
|
97
112
|
endpoint: str,
|
98
113
|
result_class: Type[TResult],
|
99
|
-
data: str | BaseModel |
|
114
|
+
data: str | BaseModel | Mapping[str, Any] | None = None,
|
100
115
|
files: Optional[List[Tuple]] = None,
|
101
116
|
poll_result: bool = True,
|
102
117
|
url: Optional[str] = None,
|
@@ -122,7 +137,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
122
137
|
data = {}
|
123
138
|
|
124
139
|
# Normalize.
|
125
|
-
data = cast(dict[str, Any], to_jsonable_python(data))
|
140
|
+
data = cast(dict[str, Any], to_jsonable_python(data, exclude_none=True))
|
126
141
|
|
127
142
|
if url is None:
|
128
143
|
url = self._url(endpoint)
|
@@ -141,8 +156,11 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
141
156
|
endpoint, result_class=result_class, data=data, files=files
|
142
157
|
)
|
143
158
|
else:
|
159
|
+
headers = self._headers()
|
160
|
+
if transfer_method == TransferMethod.MULTIPART.value:
|
161
|
+
del headers["Content-Type"]
|
144
162
|
requests_response = await self._http_post(
|
145
|
-
url, headers=
|
163
|
+
url, headers=headers, data=data, files=files, presigned_url_post=False
|
146
164
|
)
|
147
165
|
|
148
166
|
await self._check_http_errors(requests_response)
|
@@ -168,7 +186,9 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
168
186
|
|
169
187
|
pangea_response_obj = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
|
170
188
|
except aiohttp.ContentTypeError as e:
|
171
|
-
raise pe.PangeaException(
|
189
|
+
raise pe.PangeaException(
|
190
|
+
f"Failed to decode json response. {e}. Body: {await requests_response.text()}"
|
191
|
+
) from e
|
172
192
|
|
173
193
|
if poll_result:
|
174
194
|
pangea_response_obj = await self._handle_queued_result(pangea_response_obj)
|
@@ -290,7 +310,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
290
310
|
|
291
311
|
return await self.poll_result_by_id(request_id, response.result_class, check_response=check_response)
|
292
312
|
|
293
|
-
async def post_presigned_url(self, url: str, data:
|
313
|
+
async def post_presigned_url(self, url: str, data: dict[Any, Any], files: Sequence[Tuple]):
|
294
314
|
# Send form request with file and upload_details as body
|
295
315
|
resp = await self._http_post(url=url, data=data, files=files, presigned_url_post=True)
|
296
316
|
self.logger.debug(
|
@@ -412,35 +432,44 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
412
432
|
async def _http_post(
|
413
433
|
self,
|
414
434
|
url: str,
|
415
|
-
headers: Mapping[str, str
|
416
|
-
data:
|
417
|
-
files:
|
435
|
+
headers: Mapping[str, str] = {},
|
436
|
+
data: str | dict[str, Any] | None = None,
|
437
|
+
files: _Files | None = None,
|
418
438
|
presigned_url_post: bool = False,
|
419
439
|
) -> aiohttp.ClientResponse:
|
440
|
+
if data is None:
|
441
|
+
data = {}
|
442
|
+
|
420
443
|
if files:
|
421
444
|
form = FormData()
|
422
445
|
if presigned_url_post:
|
423
|
-
|
446
|
+
assert isinstance(data, dict)
|
447
|
+
assert isinstance(files, list)
|
448
|
+
for k, v in data.items():
|
424
449
|
form.add_field(k, v)
|
425
|
-
for
|
450
|
+
for _name, value in files:
|
426
451
|
form.add_field("file", value[1], filename=value[0], content_type=value[2])
|
427
452
|
else:
|
428
|
-
|
453
|
+
assert isinstance(files, list)
|
454
|
+
data_send: str | FormData = (
|
455
|
+
json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
|
456
|
+
)
|
429
457
|
form.add_field("request", data_send, content_type="application/json")
|
430
458
|
for name, value in files:
|
431
459
|
form.add_field(name, value[1], filename=value[0], content_type=value[2])
|
432
460
|
|
433
|
-
data_send = form
|
461
|
+
data_send = form
|
434
462
|
else:
|
435
463
|
data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
|
436
464
|
|
465
|
+
assert isinstance(self.session, aiohttp.ClientSession)
|
437
466
|
return await self.session.post(url, headers=headers, data=data_send)
|
438
467
|
|
439
468
|
async def _http_put(
|
440
469
|
self,
|
441
470
|
url: str,
|
442
471
|
files: Sequence[Tuple],
|
443
|
-
headers:
|
472
|
+
headers: Mapping[str, str] = {},
|
444
473
|
) -> aiohttp.ClientResponse:
|
445
474
|
self.logger.debug(
|
446
475
|
json.dumps({"service": self.service, "action": "http_put", "url": url}, default=default_encoder)
|
@@ -452,8 +481,8 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
452
481
|
self,
|
453
482
|
endpoint: str,
|
454
483
|
result_class: Type[PangeaResponseResult],
|
455
|
-
data: Union[str,
|
456
|
-
files:
|
484
|
+
data: Union[str, Mapping[str, Any]] = {},
|
485
|
+
files: Sequence[Tuple] = [],
|
457
486
|
):
|
458
487
|
if len(files) == 0:
|
459
488
|
raise AttributeError("files attribute should have at least 1 file")
|
@@ -477,7 +506,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
477
506
|
self,
|
478
507
|
endpoint: str,
|
479
508
|
result_class: Type[PangeaResponseResult],
|
480
|
-
data: Union[str,
|
509
|
+
data: Union[str, Mapping[str, Any]] = {},
|
481
510
|
) -> PangeaResponse:
|
482
511
|
# Send request
|
483
512
|
try:
|
@@ -528,7 +557,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
528
557
|
{"service": self.service, "action": "poll_presigned_url", "step": "exit", "cause": {str(e)}}
|
529
558
|
)
|
530
559
|
)
|
531
|
-
raise pe.PresignedURLException("Failed to pull Presigned URL", loop_exc.response, e)
|
560
|
+
raise pe.PresignedURLException("Failed to pull Presigned URL", loop_exc.response, e) from e
|
532
561
|
|
533
562
|
self.logger.debug(json.dumps({"service": self.service, "action": "poll_presigned_url", "step": "exit"}))
|
534
563
|
|
@@ -560,6 +589,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
560
589
|
self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_retry", "step": "exit"}))
|
561
590
|
return self._check_response(response)
|
562
591
|
|
592
|
+
@override
|
563
593
|
def _init_session(self) -> aiohttp.ClientSession:
|
564
594
|
# retry_config = Retry(
|
565
595
|
# total=self.config.request_retries,
|
@@ -1,13 +1,24 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from collections.abc import Mapping
|
3
4
|
from typing import overload
|
4
5
|
|
5
|
-
from typing_extensions import TypeVar
|
6
|
+
from typing_extensions import Literal, TypeVar
|
6
7
|
|
7
8
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
8
9
|
from pangea.config import PangeaConfig
|
9
10
|
from pangea.response import PangeaResponse
|
10
|
-
from pangea.services.ai_guard import
|
11
|
+
from pangea.services.ai_guard import (
|
12
|
+
AuditDataActivityConfig,
|
13
|
+
ConnectionsConfig,
|
14
|
+
LogFields,
|
15
|
+
Overrides,
|
16
|
+
RecipeConfig,
|
17
|
+
ServiceConfig,
|
18
|
+
ServiceConfigFilter,
|
19
|
+
ServiceConfigsPage,
|
20
|
+
TextGuardResult,
|
21
|
+
)
|
11
22
|
|
12
23
|
_T = TypeVar("_T")
|
13
24
|
|
@@ -170,3 +181,81 @@ class AIGuardAsync(ServiceBaseAsync):
|
|
170
181
|
"log_fields": log_fields,
|
171
182
|
},
|
172
183
|
)
|
184
|
+
|
185
|
+
async def get_service_config(self, id: str) -> PangeaResponse[ServiceConfig]:
|
186
|
+
"""
|
187
|
+
OperationId: ai_guard_post_v1beta_config
|
188
|
+
"""
|
189
|
+
return await self.request.post("v1beta/config", data={"id": id}, result_class=ServiceConfig)
|
190
|
+
|
191
|
+
async def create_service_config(
|
192
|
+
self,
|
193
|
+
name: str,
|
194
|
+
*,
|
195
|
+
id: str | None = None,
|
196
|
+
audit_data_activity: AuditDataActivityConfig | None = None,
|
197
|
+
connections: ConnectionsConfig | None = None,
|
198
|
+
recipes: Mapping[str, RecipeConfig] | None = None,
|
199
|
+
) -> PangeaResponse[ServiceConfig]:
|
200
|
+
"""
|
201
|
+
OperationId: ai_guard_post_v1beta_config_create
|
202
|
+
"""
|
203
|
+
return await self.request.post(
|
204
|
+
"v1beta/config/create",
|
205
|
+
data={
|
206
|
+
"name": name,
|
207
|
+
"id": id,
|
208
|
+
"audit_data_activity": audit_data_activity,
|
209
|
+
"connections": connections,
|
210
|
+
"recipes": recipes,
|
211
|
+
},
|
212
|
+
result_class=ServiceConfig,
|
213
|
+
)
|
214
|
+
|
215
|
+
async def update_service_config(
|
216
|
+
self,
|
217
|
+
id: str,
|
218
|
+
name: str,
|
219
|
+
*,
|
220
|
+
audit_data_activity: AuditDataActivityConfig | None = None,
|
221
|
+
connections: ConnectionsConfig | None = None,
|
222
|
+
recipes: Mapping[str, RecipeConfig] | None = None,
|
223
|
+
) -> PangeaResponse[ServiceConfig]:
|
224
|
+
"""
|
225
|
+
OperationId: ai_guard_post_v1beta_config_update
|
226
|
+
"""
|
227
|
+
return await self.request.post(
|
228
|
+
"v1beta/config/update",
|
229
|
+
data={
|
230
|
+
"id": id,
|
231
|
+
"name": name,
|
232
|
+
"audit_data_activity": audit_data_activity,
|
233
|
+
"connections": connections,
|
234
|
+
"recipes": recipes,
|
235
|
+
},
|
236
|
+
result_class=ServiceConfig,
|
237
|
+
)
|
238
|
+
|
239
|
+
async def delete_service_config(self, id: str) -> PangeaResponse[ServiceConfig]:
|
240
|
+
"""
|
241
|
+
OperationId: ai_guard_post_v1beta_config_delete
|
242
|
+
"""
|
243
|
+
return await self.request.post("v1beta/config/delete", data={"id": id}, result_class=ServiceConfig)
|
244
|
+
|
245
|
+
async def list_service_configs(
|
246
|
+
self,
|
247
|
+
*,
|
248
|
+
filter: ServiceConfigFilter | None = None,
|
249
|
+
last: str | None = None,
|
250
|
+
order: Literal["asc", "desc"] | None = None,
|
251
|
+
order_by: Literal["id", "created_at", "updated_at"] | None = None,
|
252
|
+
size: int | None = None,
|
253
|
+
) -> PangeaResponse[ServiceConfigsPage]:
|
254
|
+
"""
|
255
|
+
OperationId: ai_guard_post_v1beta_config_list
|
256
|
+
"""
|
257
|
+
return await self.request.post(
|
258
|
+
"v1beta/config/list",
|
259
|
+
data={"filter": filter, "last": last, "order": order, "order_by": order_by, "size": size},
|
260
|
+
result_class=ServiceConfigsPage,
|
261
|
+
)
|
@@ -1,11 +1,17 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
# TODO: Modernize.
|
5
|
+
# ruff: noqa: UP006, UP035
|
6
|
+
|
3
7
|
from __future__ import annotations
|
4
8
|
|
5
9
|
import datetime
|
6
|
-
from
|
10
|
+
from collections.abc import Mapping
|
11
|
+
from typing import Any, Dict, Iterable, List, Optional, Sequence, Union, cast, overload
|
7
12
|
|
8
13
|
from pydantic import TypeAdapter
|
14
|
+
from typing_extensions import Literal
|
9
15
|
|
10
16
|
import pangea.exceptions as pexc
|
11
17
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
@@ -70,7 +76,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
70
76
|
token: str,
|
71
77
|
config: PangeaConfig | None = None,
|
72
78
|
private_key_file: str = "",
|
73
|
-
public_key_info:
|
79
|
+
public_key_info: Mapping[str, str] = {},
|
74
80
|
tenant_id: str | None = None,
|
75
81
|
logger_name: str = "pangea",
|
76
82
|
config_id: str | None = None,
|
@@ -142,7 +148,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
142
148
|
A PangeaResponse where the hash of event data and optional verbose
|
143
149
|
results are returned in the response.result field.
|
144
150
|
Available response fields can be found in our
|
145
|
-
[API documentation](https://pangea.cloud/docs/api/audit
|
151
|
+
[API documentation](https://pangea.cloud/docs/api/audit#/v1/log-post).
|
146
152
|
|
147
153
|
Examples:
|
148
154
|
try:
|
@@ -193,7 +199,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
193
199
|
Returns:
|
194
200
|
A PangeaResponse where the hash of event data and optional verbose
|
195
201
|
results are returned in the response.result field.
|
196
|
-
Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit
|
202
|
+
Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v1/log-post).
|
197
203
|
|
198
204
|
Examples:
|
199
205
|
response = await audit.log_event({"message": "hello world"}, verbose=True)
|
@@ -229,7 +235,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
229
235
|
Returns:
|
230
236
|
A PangeaResponse where the hash of event data and optional verbose
|
231
237
|
results are returned in the response.result field.
|
232
|
-
Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit
|
238
|
+
Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v1/log-post).
|
233
239
|
|
234
240
|
Examples:
|
235
241
|
FIXME:
|
@@ -266,7 +272,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
266
272
|
Returns:
|
267
273
|
A PangeaResponse where the hash of event data and optional verbose
|
268
274
|
results are returned in the response.result field.
|
269
|
-
Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit
|
275
|
+
Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v1/log-post).
|
270
276
|
|
271
277
|
Examples:
|
272
278
|
FIXME:
|
@@ -335,8 +341,8 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
335
341
|
|
336
342
|
Returns:
|
337
343
|
A PangeaResponse[SearchOutput] where the first page of matched events is returned in the
|
338
|
-
response.result field. Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit
|
339
|
-
Pagination can be found in the [search results endpoint](https://pangea.cloud/docs/api/audit
|
344
|
+
response.result field. Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v1/results-post).
|
345
|
+
Pagination can be found in the [search results endpoint](https://pangea.cloud/docs/api/audit#/v1/download_results-post).
|
340
346
|
|
341
347
|
Examples:
|
342
348
|
response: PangeaResponse[SearchOutput] = audit.search(query="message:test", search_restriction={'source': ["monitor"]}, limit=1, verify_consistency=True, verify_events=True)
|