pangea-sdk 6.2.0b1__py3-none-any.whl → 6.3.0__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.
- pangea/__init__.py +9 -1
- pangea/asyncio/__init__.py +1 -0
- pangea/asyncio/file_uploader.py +4 -2
- pangea/asyncio/request.py +70 -169
- pangea/asyncio/services/__init__.py +2 -1
- pangea/asyncio/services/ai_guard.py +9 -12
- pangea/asyncio/services/audit.py +13 -307
- pangea/asyncio/services/authn.py +40 -32
- pangea/asyncio/services/authz.py +51 -17
- pangea/asyncio/services/base.py +4 -0
- pangea/asyncio/services/file_scan.py +8 -2
- pangea/asyncio/services/intel.py +26 -28
- pangea/asyncio/services/redact.py +11 -268
- pangea/asyncio/services/sanitize.py +5 -1
- pangea/asyncio/services/share.py +5 -1
- pangea/asyncio/services/vault.py +71 -55
- pangea/audit_logger.py +3 -1
- pangea/deep_verify.py +13 -13
- pangea/deprecated.py +1 -1
- pangea/dump_audit.py +2 -3
- pangea/exceptions.py +8 -5
- pangea/file_uploader.py +4 -0
- pangea/request.py +80 -200
- pangea/response.py +21 -18
- pangea/services/__init__.py +2 -1
- pangea/services/ai_guard.py +35 -24
- pangea/services/audit/audit.py +17 -314
- pangea/services/audit/models.py +69 -307
- pangea/services/audit/signing.py +1 -1
- pangea/services/audit/util.py +10 -10
- pangea/services/authn/authn.py +39 -31
- pangea/services/authn/models.py +183 -148
- pangea/services/authz.py +108 -60
- pangea/services/base.py +7 -4
- pangea/services/embargo.py +6 -0
- pangea/services/file_scan.py +8 -2
- pangea/services/intel.py +36 -19
- pangea/services/redact.py +14 -476
- pangea/services/sanitize.py +5 -1
- pangea/services/share/share.py +13 -7
- pangea/services/vault/models/asymmetric.py +4 -0
- pangea/services/vault/models/common.py +15 -12
- pangea/services/vault/models/keys.py +4 -9
- pangea/services/vault/models/secret.py +3 -8
- pangea/services/vault/models/symmetric.py +4 -0
- pangea/services/vault/vault.py +69 -59
- pangea/tools.py +13 -9
- pangea/utils.py +3 -5
- pangea/verify_audit.py +23 -27
- {pangea_sdk-6.2.0b1.dist-info → pangea_sdk-6.3.0.dist-info}/METADATA +36 -17
- pangea_sdk-6.3.0.dist-info/RECORD +60 -0
- {pangea_sdk-6.2.0b1.dist-info → pangea_sdk-6.3.0.dist-info}/WHEEL +1 -1
- pangea/asyncio/services/management.py +0 -576
- pangea/services/management.py +0 -720
- pangea_sdk-6.2.0b1.dist-info/RECORD +0 -62
pangea/__init__.py
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
-
__version__ = "6.
|
1
|
+
__version__ = "6.3.0"
|
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
|
+
)
|
pangea/asyncio/__init__.py
CHANGED
pangea/asyncio/file_uploader.py
CHANGED
@@ -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"))]
|
pangea/asyncio/request.py
CHANGED
@@ -1,24 +1,43 @@
|
|
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
|
10
14
|
|
11
15
|
import aiohttp
|
12
16
|
from aiohttp import FormData
|
13
|
-
from pydantic import BaseModel
|
17
|
+
from pydantic import BaseModel
|
14
18
|
from pydantic_core import to_jsonable_python
|
15
|
-
from typing_extensions import Any, TypeVar
|
19
|
+
from typing_extensions import Any, 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
|
+
_LooseHeaders = Union[
|
36
|
+
Mapping[str, str],
|
37
|
+
Iterable[tuple[str, str]],
|
38
|
+
]
|
39
|
+
|
40
|
+
|
22
41
|
TResult = TypeVar("TResult", bound=PangeaResponseResult)
|
23
42
|
|
24
43
|
|
@@ -31,86 +50,26 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
31
50
|
be set in PangeaConfig.
|
32
51
|
"""
|
33
52
|
|
34
|
-
async def delete(self, endpoint: str) -> None:
|
35
|
-
"""
|
36
|
-
Makes a DELETE call to a Pangea endpoint.
|
37
|
-
|
38
|
-
Args:
|
39
|
-
endpoint: The Pangea API endpoint.
|
40
|
-
"""
|
41
|
-
|
42
|
-
url = self._url(endpoint)
|
43
|
-
|
44
|
-
self.logger.debug(
|
45
|
-
json.dumps({"service": self.service, "action": "delete", "url": url}, default=default_encoder)
|
46
|
-
)
|
47
|
-
|
48
|
-
requests_response = await self._http_delete(url, headers=self._headers())
|
49
|
-
await self._check_http_errors(requests_response)
|
50
|
-
|
51
|
-
@overload
|
52
53
|
async def post(
|
53
54
|
self,
|
54
55
|
endpoint: str,
|
55
56
|
result_class: Type[TResult],
|
56
|
-
data: str | BaseModel |
|
57
|
+
data: str | BaseModel | Mapping[str, Any] | None = None,
|
57
58
|
files: Optional[List[Tuple]] = None,
|
58
59
|
poll_result: bool = True,
|
59
60
|
url: Optional[str] = None,
|
60
|
-
*,
|
61
|
-
pangea_response: Literal[True] = True,
|
62
61
|
) -> PangeaResponse[TResult]:
|
63
|
-
"""
|
64
|
-
Makes a POST call to a Pangea Service endpoint.
|
62
|
+
"""Makes the POST call to a Pangea Service endpoint.
|
65
63
|
|
66
64
|
Args:
|
67
|
-
endpoint: The Pangea Service API endpoint.
|
68
|
-
data: The POST body payload object
|
65
|
+
endpoint(str): The Pangea Service API endpoint.
|
66
|
+
data(dict): The POST body payload object
|
69
67
|
|
70
68
|
Returns:
|
71
69
|
PangeaResponse which contains the response in its entirety and
|
72
70
|
various properties to retrieve individual fields
|
73
71
|
"""
|
74
72
|
|
75
|
-
@overload
|
76
|
-
async def post(
|
77
|
-
self,
|
78
|
-
endpoint: str,
|
79
|
-
result_class: Type[TResult],
|
80
|
-
data: str | BaseModel | dict[str, Any] | None = None,
|
81
|
-
files: Optional[List[Tuple]] = None,
|
82
|
-
poll_result: bool = True,
|
83
|
-
url: Optional[str] = None,
|
84
|
-
*,
|
85
|
-
pangea_response: Literal[False],
|
86
|
-
) -> TResult:
|
87
|
-
"""
|
88
|
-
Makes a POST call to a Pangea Service endpoint.
|
89
|
-
|
90
|
-
Args:
|
91
|
-
endpoint: The Pangea Service API endpoint.
|
92
|
-
data: The POST body payload object
|
93
|
-
"""
|
94
|
-
|
95
|
-
async def post(
|
96
|
-
self,
|
97
|
-
endpoint: str,
|
98
|
-
result_class: Type[TResult],
|
99
|
-
data: str | BaseModel | dict[str, Any] | None = None,
|
100
|
-
files: Optional[List[Tuple]] = None,
|
101
|
-
poll_result: bool = True,
|
102
|
-
url: Optional[str] = None,
|
103
|
-
*,
|
104
|
-
pangea_response: bool = True,
|
105
|
-
) -> PangeaResponse[TResult] | TResult:
|
106
|
-
"""
|
107
|
-
Makes a POST call to a Pangea Service endpoint.
|
108
|
-
|
109
|
-
Args:
|
110
|
-
endpoint: The Pangea Service API endpoint.
|
111
|
-
data: The POST body payload object
|
112
|
-
"""
|
113
|
-
|
114
73
|
if isinstance(data, BaseModel):
|
115
74
|
data = data.model_dump(exclude_none=True)
|
116
75
|
|
@@ -122,7 +81,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
122
81
|
data = {}
|
123
82
|
|
124
83
|
# Normalize.
|
125
|
-
data = cast(dict[str, Any], to_jsonable_python(data))
|
84
|
+
data = cast(dict[str, Any], to_jsonable_python(data, exclude_none=True))
|
126
85
|
|
127
86
|
if url is None:
|
128
87
|
url = self._url(endpoint)
|
@@ -141,19 +100,18 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
141
100
|
endpoint, result_class=result_class, data=data, files=files
|
142
101
|
)
|
143
102
|
else:
|
103
|
+
headers = self._headers()
|
104
|
+
if transfer_method == TransferMethod.MULTIPART.value:
|
105
|
+
del headers["Content-Type"]
|
144
106
|
requests_response = await self._http_post(
|
145
|
-
url, headers=
|
107
|
+
url, headers=headers, data=data, files=files, presigned_url_post=False
|
146
108
|
)
|
147
109
|
|
148
110
|
await self._check_http_errors(requests_response)
|
149
111
|
|
150
|
-
if not pangea_response:
|
151
|
-
type_adapter = TypeAdapter(result_class)
|
152
|
-
return type_adapter.validate_python(await requests_response.json())
|
153
|
-
|
154
112
|
if "multipart/form-data" in requests_response.headers.get("content-type", ""):
|
155
113
|
multipart_response = await self._process_multipart_response(requests_response)
|
156
|
-
|
114
|
+
pangea_response: PangeaResponse = PangeaResponse(
|
157
115
|
requests_response,
|
158
116
|
result_class=result_class,
|
159
117
|
json=multipart_response.pangea_json,
|
@@ -166,108 +124,49 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
166
124
|
json.dumps({"service": self.service, "action": "post", "url": url, "response": json_resp})
|
167
125
|
)
|
168
126
|
|
169
|
-
|
127
|
+
pangea_response = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
|
170
128
|
except aiohttp.ContentTypeError as e:
|
171
|
-
raise pe.PangeaException(
|
129
|
+
raise pe.PangeaException(
|
130
|
+
f"Failed to decode json response. {e}. Body: {await requests_response.text()}"
|
131
|
+
) from e
|
172
132
|
|
173
133
|
if poll_result:
|
174
|
-
|
134
|
+
pangea_response = await self._handle_queued_result(pangea_response)
|
175
135
|
|
176
|
-
return self._check_response(
|
136
|
+
return self._check_response(pangea_response)
|
177
137
|
|
178
|
-
|
179
|
-
|
180
|
-
self,
|
181
|
-
path: str,
|
182
|
-
result_class: Type[TResult],
|
183
|
-
check_response: bool = True,
|
184
|
-
*,
|
185
|
-
params: (
|
186
|
-
Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
|
187
|
-
| None
|
188
|
-
) = None,
|
189
|
-
pangea_response: Literal[True] = True,
|
190
|
-
) -> PangeaResponse[TResult]:
|
191
|
-
"""
|
192
|
-
Makes the GET call to a Pangea Service endpoint.
|
138
|
+
async def get(self, path: str, result_class: Type[TResult], check_response: bool = True) -> PangeaResponse[TResult]:
|
139
|
+
"""Makes the GET call to a Pangea Service endpoint.
|
193
140
|
|
194
141
|
Args:
|
195
|
-
|
196
|
-
|
142
|
+
endpoint(str): The Pangea Service API endpoint.
|
143
|
+
path(str): Additional URL path
|
197
144
|
|
198
145
|
Returns:
|
199
146
|
PangeaResponse which contains the response in its entirety and
|
200
147
|
various properties to retrieve individual fields
|
201
148
|
"""
|
202
149
|
|
203
|
-
@overload
|
204
|
-
async def get(
|
205
|
-
self,
|
206
|
-
path: str,
|
207
|
-
result_class: Type[TResult],
|
208
|
-
check_response: bool = True,
|
209
|
-
*,
|
210
|
-
params: (
|
211
|
-
Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
|
212
|
-
| None
|
213
|
-
) = None,
|
214
|
-
pangea_response: Literal[False] = False,
|
215
|
-
) -> TResult:
|
216
|
-
"""
|
217
|
-
Makes the GET call to a Pangea Service endpoint.
|
218
|
-
|
219
|
-
Args:
|
220
|
-
path: Additional URL path
|
221
|
-
params: Dictionary of querystring data to attach to the request
|
222
|
-
"""
|
223
|
-
|
224
|
-
async def get(
|
225
|
-
self,
|
226
|
-
path: str,
|
227
|
-
result_class: Type[TResult],
|
228
|
-
check_response: bool = True,
|
229
|
-
*,
|
230
|
-
params: (
|
231
|
-
Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
|
232
|
-
| None
|
233
|
-
) = None,
|
234
|
-
pangea_response: bool = True,
|
235
|
-
) -> PangeaResponse[TResult] | TResult:
|
236
|
-
"""
|
237
|
-
Makes the GET call to a Pangea Service endpoint.
|
238
|
-
|
239
|
-
Args:
|
240
|
-
path: Additional URL path
|
241
|
-
params: Dictionary of querystring data to attach to the request
|
242
|
-
pangea_response: Whether or not the response body follows Pangea's
|
243
|
-
standard response schema
|
244
|
-
"""
|
245
|
-
|
246
150
|
url = self._url(path)
|
247
151
|
self.logger.debug(json.dumps({"service": self.service, "action": "get", "url": url}))
|
248
152
|
|
249
|
-
async with self.session.get(url,
|
153
|
+
async with self.session.get(url, headers=self._headers()) as requests_response:
|
250
154
|
await self._check_http_errors(requests_response)
|
251
|
-
|
252
|
-
if not pangea_response:
|
253
|
-
type_adapter = TypeAdapter(result_class)
|
254
|
-
return type_adapter.validate_python(await requests_response.json())
|
255
|
-
|
256
|
-
pangea_response_obj = PangeaResponse(
|
155
|
+
pangea_response = PangeaResponse(
|
257
156
|
requests_response, result_class=result_class, json=await requests_response.json()
|
258
157
|
)
|
259
158
|
|
260
159
|
self.logger.debug(
|
261
160
|
json.dumps(
|
262
|
-
{"service": self.service, "action": "get", "url": url, "response":
|
161
|
+
{"service": self.service, "action": "get", "url": url, "response": pangea_response.json},
|
263
162
|
default=default_encoder,
|
264
163
|
)
|
265
164
|
)
|
266
165
|
|
267
166
|
if check_response is False:
|
268
|
-
return
|
167
|
+
return pangea_response
|
269
168
|
|
270
|
-
return self._check_response(
|
169
|
+
return self._check_response(pangea_response)
|
271
170
|
|
272
171
|
async def _check_http_errors(self, resp: aiohttp.ClientResponse):
|
273
172
|
if resp.status == 503:
|
@@ -290,7 +189,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
290
189
|
|
291
190
|
return await self.poll_result_by_id(request_id, response.result_class, check_response=check_response)
|
292
191
|
|
293
|
-
async def post_presigned_url(self, url: str, data:
|
192
|
+
async def post_presigned_url(self, url: str, data: dict[Any, Any], files: Sequence[Tuple]):
|
294
193
|
# Send form request with file and upload_details as body
|
295
194
|
resp = await self._http_post(url=url, data=data, files=files, presigned_url_post=True)
|
296
195
|
self.logger.debug(
|
@@ -401,46 +300,47 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
401
300
|
attached_files = await self._get_attached_files(multipart_reader)
|
402
301
|
return MultipartResponse(pangea_json, attached_files) # type: ignore[arg-type]
|
403
302
|
|
404
|
-
async def _http_delete(
|
405
|
-
self,
|
406
|
-
url: str,
|
407
|
-
*,
|
408
|
-
headers: Mapping[str, str | bytes | None] = {},
|
409
|
-
) -> aiohttp.ClientResponse:
|
410
|
-
return await self.session.delete(url, headers=headers)
|
411
|
-
|
412
303
|
async def _http_post(
|
413
304
|
self,
|
414
305
|
url: str,
|
415
|
-
headers:
|
416
|
-
data:
|
417
|
-
files:
|
306
|
+
headers: _LooseHeaders = {}, # noqa: B006
|
307
|
+
data: str | dict[str, Any] | None = None,
|
308
|
+
files: _Files | None = None,
|
418
309
|
presigned_url_post: bool = False,
|
419
310
|
) -> aiohttp.ClientResponse:
|
311
|
+
if data is None:
|
312
|
+
data = {}
|
313
|
+
|
420
314
|
if files:
|
421
315
|
form = FormData()
|
422
316
|
if presigned_url_post:
|
423
|
-
|
317
|
+
assert isinstance(data, dict)
|
318
|
+
assert isinstance(files, list)
|
319
|
+
for k, v in data.items():
|
424
320
|
form.add_field(k, v)
|
425
|
-
for
|
321
|
+
for _name, value in files:
|
426
322
|
form.add_field("file", value[1], filename=value[0], content_type=value[2])
|
427
323
|
else:
|
428
|
-
|
324
|
+
assert isinstance(files, list)
|
325
|
+
data_send: str | FormData = (
|
326
|
+
json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
|
327
|
+
)
|
429
328
|
form.add_field("request", data_send, content_type="application/json")
|
430
329
|
for name, value in files:
|
431
330
|
form.add_field(name, value[1], filename=value[0], content_type=value[2])
|
432
331
|
|
433
|
-
data_send = form
|
332
|
+
data_send = form
|
434
333
|
else:
|
435
334
|
data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
|
436
335
|
|
336
|
+
assert isinstance(self.session, aiohttp.ClientSession)
|
437
337
|
return await self.session.post(url, headers=headers, data=data_send)
|
438
338
|
|
439
339
|
async def _http_put(
|
440
340
|
self,
|
441
341
|
url: str,
|
442
342
|
files: Sequence[Tuple],
|
443
|
-
headers:
|
343
|
+
headers: _LooseHeaders = {}, # noqa: B006
|
444
344
|
) -> aiohttp.ClientResponse:
|
445
345
|
self.logger.debug(
|
446
346
|
json.dumps({"service": self.service, "action": "http_put", "url": url}, default=default_encoder)
|
@@ -452,8 +352,8 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
452
352
|
self,
|
453
353
|
endpoint: str,
|
454
354
|
result_class: Type[PangeaResponseResult],
|
455
|
-
data: Union[str,
|
456
|
-
files:
|
355
|
+
data: Union[str, Mapping[str, Any]] = {},
|
356
|
+
files: Sequence[Tuple] = [],
|
457
357
|
):
|
458
358
|
if len(files) == 0:
|
459
359
|
raise AttributeError("files attribute should have at least 1 file")
|
@@ -477,7 +377,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
477
377
|
self,
|
478
378
|
endpoint: str,
|
479
379
|
result_class: Type[PangeaResponseResult],
|
480
|
-
data: Union[str,
|
380
|
+
data: Union[str, Mapping[str, Any]] = {},
|
481
381
|
) -> PangeaResponse:
|
482
382
|
# Send request
|
483
383
|
try:
|
@@ -528,7 +428,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
528
428
|
{"service": self.service, "action": "poll_presigned_url", "step": "exit", "cause": {str(e)}}
|
529
429
|
)
|
530
430
|
)
|
531
|
-
raise pe.PresignedURLException("Failed to pull Presigned URL", loop_exc.response, e)
|
431
|
+
raise pe.PresignedURLException("Failed to pull Presigned URL", loop_exc.response, e) from e
|
532
432
|
|
533
433
|
self.logger.debug(json.dumps({"service": self.service, "action": "poll_presigned_url", "step": "exit"}))
|
534
434
|
|
@@ -560,6 +460,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
560
460
|
self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_retry", "step": "exit"}))
|
561
461
|
return self._check_response(response)
|
562
462
|
|
463
|
+
@override
|
563
464
|
def _init_session(self) -> aiohttp.ClientSession:
|
564
465
|
# retry_config = Retry(
|
565
466
|
# total=self.config.request_retries,
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# ruff: noqa: F401
|
2
|
+
|
1
3
|
from .ai_guard import AIGuardAsync
|
2
4
|
from .audit import AuditAsync
|
3
5
|
from .authn import AuthNAsync
|
@@ -5,7 +7,6 @@ from .authz import AuthZAsync
|
|
5
7
|
from .embargo import EmbargoAsync
|
6
8
|
from .file_scan import FileScanAsync
|
7
9
|
from .intel import DomainIntelAsync, FileIntelAsync, IpIntelAsync, UrlIntelAsync, UserIntelAsync
|
8
|
-
from .management import ManagementAsync
|
9
10
|
from .prompt_guard import PromptGuardAsync
|
10
11
|
from .redact import RedactAsync
|
11
12
|
from .sanitize import SanitizeAsync
|
@@ -1,15 +1,12 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from collections.abc import Sequence
|
3
4
|
from typing import overload
|
4
5
|
|
5
|
-
from typing_extensions import TypeVar
|
6
|
-
|
7
6
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
8
7
|
from pangea.config import PangeaConfig
|
9
8
|
from pangea.response import PangeaResponse
|
10
|
-
from pangea.services.ai_guard import LogFields, Overrides, TextGuardResult
|
11
|
-
|
12
|
-
_T = TypeVar("_T")
|
9
|
+
from pangea.services.ai_guard import LogFields, Message, Overrides, TextGuardResult
|
13
10
|
|
14
11
|
|
15
12
|
class AIGuardAsync(ServiceBaseAsync):
|
@@ -60,7 +57,7 @@ class AIGuardAsync(ServiceBaseAsync):
|
|
60
57
|
debug: bool | None = None,
|
61
58
|
overrides: Overrides | None = None,
|
62
59
|
log_fields: LogFields | None = None,
|
63
|
-
) -> PangeaResponse[TextGuardResult
|
60
|
+
) -> PangeaResponse[TextGuardResult]:
|
64
61
|
"""
|
65
62
|
Text Guard for scanning LLM inputs and outputs
|
66
63
|
|
@@ -88,12 +85,12 @@ class AIGuardAsync(ServiceBaseAsync):
|
|
88
85
|
async def guard_text(
|
89
86
|
self,
|
90
87
|
*,
|
91
|
-
messages:
|
88
|
+
messages: Sequence[Message],
|
92
89
|
recipe: str | None = None,
|
93
90
|
debug: bool | None = None,
|
94
91
|
overrides: Overrides | None = None,
|
95
92
|
log_fields: LogFields | None = None,
|
96
|
-
) -> PangeaResponse[TextGuardResult
|
93
|
+
) -> PangeaResponse[TextGuardResult]:
|
97
94
|
"""
|
98
95
|
Text Guard for scanning LLM inputs and outputs
|
99
96
|
|
@@ -115,19 +112,19 @@ class AIGuardAsync(ServiceBaseAsync):
|
|
115
112
|
log_field: Additional fields to include in activity log
|
116
113
|
|
117
114
|
Examples:
|
118
|
-
response = await ai_guard.guard_text(messages=[
|
115
|
+
response = await ai_guard.guard_text(messages=[Message(role="user", content="hello world")])
|
119
116
|
"""
|
120
117
|
|
121
|
-
async def guard_text(
|
118
|
+
async def guard_text(
|
122
119
|
self,
|
123
120
|
text: str | None = None,
|
124
121
|
*,
|
125
|
-
messages:
|
122
|
+
messages: Sequence[Message] | None = None,
|
126
123
|
recipe: str | None = None,
|
127
124
|
debug: bool | None = None,
|
128
125
|
overrides: Overrides | None = None,
|
129
126
|
log_fields: LogFields | None = None,
|
130
|
-
) -> PangeaResponse[TextGuardResult
|
127
|
+
) -> PangeaResponse[TextGuardResult]:
|
131
128
|
"""
|
132
129
|
Text Guard for scanning LLM inputs and outputs
|
133
130
|
|