pangea-sdk 6.1.1__py3-none-any.whl → 6.2.0b2__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 (54) hide show
  1. pangea/__init__.py +9 -1
  2. pangea/asyncio/__init__.py +1 -0
  3. pangea/asyncio/file_uploader.py +4 -2
  4. pangea/asyncio/request.py +199 -35
  5. pangea/asyncio/services/__init__.py +3 -0
  6. pangea/asyncio/services/ai_guard.py +91 -2
  7. pangea/asyncio/services/audit.py +307 -2
  8. pangea/asyncio/services/authn.py +12 -2
  9. pangea/asyncio/services/base.py +4 -0
  10. pangea/asyncio/services/file_scan.py +7 -1
  11. pangea/asyncio/services/intel.py +6 -2
  12. pangea/asyncio/services/management.py +576 -0
  13. pangea/asyncio/services/prompt_guard.py +112 -2
  14. pangea/asyncio/services/redact.py +269 -4
  15. pangea/asyncio/services/sanitize.py +5 -1
  16. pangea/asyncio/services/share.py +5 -1
  17. pangea/asyncio/services/vault.py +4 -0
  18. pangea/audit_logger.py +3 -1
  19. pangea/deep_verify.py +13 -13
  20. pangea/deprecated.py +1 -1
  21. pangea/dump_audit.py +2 -3
  22. pangea/exceptions.py +8 -5
  23. pangea/file_uploader.py +4 -0
  24. pangea/request.py +205 -52
  25. pangea/response.py +15 -12
  26. pangea/services/__init__.py +3 -0
  27. pangea/services/ai_guard.py +497 -16
  28. pangea/services/audit/audit.py +310 -8
  29. pangea/services/audit/models.py +279 -0
  30. pangea/services/audit/signing.py +1 -1
  31. pangea/services/audit/util.py +10 -10
  32. pangea/services/authn/authn.py +12 -2
  33. pangea/services/authn/models.py +3 -0
  34. pangea/services/authz.py +4 -0
  35. pangea/services/base.py +5 -1
  36. pangea/services/embargo.py +6 -0
  37. pangea/services/file_scan.py +7 -1
  38. pangea/services/intel.py +4 -0
  39. pangea/services/management.py +720 -0
  40. pangea/services/prompt_guard.py +193 -2
  41. pangea/services/redact.py +477 -7
  42. pangea/services/sanitize.py +5 -1
  43. pangea/services/share/share.py +13 -7
  44. pangea/services/vault/models/asymmetric.py +4 -0
  45. pangea/services/vault/models/common.py +4 -0
  46. pangea/services/vault/models/symmetric.py +4 -0
  47. pangea/services/vault/vault.py +2 -4
  48. pangea/tools.py +13 -9
  49. pangea/utils.py +3 -5
  50. pangea/verify_audit.py +23 -27
  51. {pangea_sdk-6.1.1.dist-info → pangea_sdk-6.2.0b2.dist-info}/METADATA +4 -4
  52. pangea_sdk-6.2.0b2.dist-info/RECORD +62 -0
  53. pangea_sdk-6.1.1.dist-info/RECORD +0 -60
  54. {pangea_sdk-6.1.1.dist-info → pangea_sdk-6.2.0b2.dist-info}/WHEEL +0 -0
pangea/__init__.py CHANGED
@@ -1,7 +1,15 @@
1
- __version__ = "6.1.1"
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 +1,2 @@
1
+ # ruff: noqa: F401
1
2
  from .file_uploader import FileUploaderAsync
@@ -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: Optional[Dict] = None,
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,23 +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
- from typing import Dict, List, Optional, Sequence, Tuple, Type, Union, cast
12
+ from collections.abc import Iterable, Mapping
13
+ from typing import Dict, List, Optional, Sequence, Tuple, Type, Union, cast, overload
9
14
 
10
15
  import aiohttp
11
16
  from aiohttp import FormData
12
- from pydantic import BaseModel
17
+ from pydantic import BaseModel, TypeAdapter
13
18
  from pydantic_core import to_jsonable_python
14
- from typing_extensions import Any, TypeVar
19
+ from typing_extensions import Any, Literal, TypeAlias, TypeVar, override
15
20
 
16
21
  import pangea.exceptions as pe
17
22
  from pangea.request import MultipartResponse, PangeaRequestBase
18
23
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
19
24
  from pangea.utils import default_encoder
20
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
+
21
37
  TResult = TypeVar("TResult", bound=PangeaResponseResult)
22
38
 
23
39
 
@@ -30,26 +46,86 @@ class PangeaRequestAsync(PangeaRequestBase):
30
46
  be set in PangeaConfig.
31
47
  """
32
48
 
49
+ async def delete(self, endpoint: str) -> None:
50
+ """
51
+ Makes a DELETE call to a Pangea endpoint.
52
+
53
+ Args:
54
+ endpoint: The Pangea API endpoint.
55
+ """
56
+
57
+ url = self._url(endpoint)
58
+
59
+ self.logger.debug(
60
+ json.dumps({"service": self.service, "action": "delete", "url": url}, default=default_encoder)
61
+ )
62
+
63
+ requests_response = await self._http_delete(url, headers=self._headers())
64
+ await self._check_http_errors(requests_response)
65
+
66
+ @overload
33
67
  async def post(
34
68
  self,
35
69
  endpoint: str,
36
70
  result_class: Type[TResult],
37
- data: str | BaseModel | dict[str, Any] | None = None,
71
+ data: str | BaseModel | Mapping[str, Any] | None = None,
38
72
  files: Optional[List[Tuple]] = None,
39
73
  poll_result: bool = True,
40
74
  url: Optional[str] = None,
75
+ *,
76
+ pangea_response: Literal[True] = True,
41
77
  ) -> PangeaResponse[TResult]:
42
- """Makes the POST call to a Pangea Service endpoint.
78
+ """
79
+ Makes a POST call to a Pangea Service endpoint.
43
80
 
44
81
  Args:
45
- endpoint(str): The Pangea Service API endpoint.
46
- data(dict): The POST body payload object
82
+ endpoint: The Pangea Service API endpoint.
83
+ data: The POST body payload object
47
84
 
48
85
  Returns:
49
86
  PangeaResponse which contains the response in its entirety and
50
87
  various properties to retrieve individual fields
51
88
  """
52
89
 
90
+ @overload
91
+ async def post(
92
+ self,
93
+ endpoint: str,
94
+ result_class: Type[TResult],
95
+ data: str | BaseModel | Mapping[str, Any] | None = None,
96
+ files: Optional[List[Tuple]] = None,
97
+ poll_result: bool = True,
98
+ url: Optional[str] = None,
99
+ *,
100
+ pangea_response: Literal[False],
101
+ ) -> TResult:
102
+ """
103
+ Makes a POST call to a Pangea Service endpoint.
104
+
105
+ Args:
106
+ endpoint: The Pangea Service API endpoint.
107
+ data: The POST body payload object
108
+ """
109
+
110
+ async def post(
111
+ self,
112
+ endpoint: str,
113
+ result_class: Type[TResult],
114
+ data: str | BaseModel | Mapping[str, Any] | None = None,
115
+ files: Optional[List[Tuple]] = None,
116
+ poll_result: bool = True,
117
+ url: Optional[str] = None,
118
+ *,
119
+ pangea_response: bool = True,
120
+ ) -> PangeaResponse[TResult] | TResult:
121
+ """
122
+ Makes a POST call to a Pangea Service endpoint.
123
+
124
+ Args:
125
+ endpoint: The Pangea Service API endpoint.
126
+ data: The POST body payload object
127
+ """
128
+
53
129
  if isinstance(data, BaseModel):
54
130
  data = data.model_dump(exclude_none=True)
55
131
 
@@ -80,15 +156,22 @@ class PangeaRequestAsync(PangeaRequestBase):
80
156
  endpoint, result_class=result_class, data=data, files=files
81
157
  )
82
158
  else:
159
+ headers = self._headers()
160
+ if transfer_method == TransferMethod.MULTIPART.value:
161
+ del headers["Content-Type"]
83
162
  requests_response = await self._http_post(
84
- url, headers=self._headers(), data=data, files=files, presigned_url_post=False
163
+ url, headers=headers, data=data, files=files, presigned_url_post=False
85
164
  )
86
165
 
87
166
  await self._check_http_errors(requests_response)
88
167
 
168
+ if not pangea_response:
169
+ type_adapter = TypeAdapter(result_class)
170
+ return type_adapter.validate_python(await requests_response.json())
171
+
89
172
  if "multipart/form-data" in requests_response.headers.get("content-type", ""):
90
173
  multipart_response = await self._process_multipart_response(requests_response)
91
- pangea_response: PangeaResponse = PangeaResponse(
174
+ pangea_response_obj: PangeaResponse = PangeaResponse(
92
175
  requests_response,
93
176
  result_class=result_class,
94
177
  json=multipart_response.pangea_json,
@@ -101,47 +184,110 @@ class PangeaRequestAsync(PangeaRequestBase):
101
184
  json.dumps({"service": self.service, "action": "post", "url": url, "response": json_resp})
102
185
  )
103
186
 
104
- pangea_response = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
187
+ pangea_response_obj = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
105
188
  except aiohttp.ContentTypeError as e:
106
- raise pe.PangeaException(f"Failed to decode json response. {e}. Body: {await requests_response.text()}")
189
+ raise pe.PangeaException(
190
+ f"Failed to decode json response. {e}. Body: {await requests_response.text()}"
191
+ ) from e
107
192
 
108
193
  if poll_result:
109
- pangea_response = await self._handle_queued_result(pangea_response)
194
+ pangea_response_obj = await self._handle_queued_result(pangea_response_obj)
110
195
 
111
- return self._check_response(pangea_response)
196
+ return self._check_response(pangea_response_obj)
112
197
 
113
- async def get(self, path: str, result_class: Type[TResult], check_response: bool = True) -> PangeaResponse[TResult]:
114
- """Makes the GET call to a Pangea Service endpoint.
198
+ @overload
199
+ async def get(
200
+ self,
201
+ path: str,
202
+ result_class: Type[TResult],
203
+ check_response: bool = True,
204
+ *,
205
+ params: (
206
+ Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
207
+ | None
208
+ ) = None,
209
+ pangea_response: Literal[True] = True,
210
+ ) -> PangeaResponse[TResult]:
211
+ """
212
+ Makes the GET call to a Pangea Service endpoint.
115
213
 
116
214
  Args:
117
- endpoint(str): The Pangea Service API endpoint.
118
- path(str): Additional URL path
215
+ path: Additional URL path
216
+ params: Dictionary of querystring data to attach to the request
119
217
 
120
218
  Returns:
121
219
  PangeaResponse which contains the response in its entirety and
122
220
  various properties to retrieve individual fields
123
221
  """
124
222
 
223
+ @overload
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: Literal[False] = False,
235
+ ) -> 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
+ """
243
+
244
+ async def get(
245
+ self,
246
+ path: str,
247
+ result_class: Type[TResult],
248
+ check_response: bool = True,
249
+ *,
250
+ params: (
251
+ Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
252
+ | None
253
+ ) = None,
254
+ pangea_response: bool = True,
255
+ ) -> PangeaResponse[TResult] | TResult:
256
+ """
257
+ Makes the GET call to a Pangea Service endpoint.
258
+
259
+ Args:
260
+ path: Additional URL path
261
+ params: Dictionary of querystring data to attach to the request
262
+ pangea_response: Whether or not the response body follows Pangea's
263
+ standard response schema
264
+ """
265
+
125
266
  url = self._url(path)
126
267
  self.logger.debug(json.dumps({"service": self.service, "action": "get", "url": url}))
127
268
 
128
- async with self.session.get(url, headers=self._headers()) as requests_response:
269
+ async with self.session.get(url, params=params, headers=self._headers()) as requests_response:
129
270
  await self._check_http_errors(requests_response)
130
- pangea_response = PangeaResponse(
271
+
272
+ if not pangea_response:
273
+ type_adapter = TypeAdapter(result_class)
274
+ return type_adapter.validate_python(await requests_response.json())
275
+
276
+ pangea_response_obj = PangeaResponse(
131
277
  requests_response, result_class=result_class, json=await requests_response.json()
132
278
  )
133
279
 
134
280
  self.logger.debug(
135
281
  json.dumps(
136
- {"service": self.service, "action": "get", "url": url, "response": pangea_response.json},
282
+ {"service": self.service, "action": "get", "url": url, "response": pangea_response_obj.json},
137
283
  default=default_encoder,
138
284
  )
139
285
  )
140
286
 
141
287
  if check_response is False:
142
- return pangea_response
288
+ return pangea_response_obj
143
289
 
144
- return self._check_response(pangea_response)
290
+ return self._check_response(pangea_response_obj)
145
291
 
146
292
  async def _check_http_errors(self, resp: aiohttp.ClientResponse):
147
293
  if resp.status == 503:
@@ -164,7 +310,7 @@ class PangeaRequestAsync(PangeaRequestBase):
164
310
 
165
311
  return await self.poll_result_by_id(request_id, response.result_class, check_response=check_response)
166
312
 
167
- async def post_presigned_url(self, url: str, data: Dict, files: List[Tuple]):
313
+ async def post_presigned_url(self, url: str, data: dict[Any, Any], files: Sequence[Tuple]):
168
314
  # Send form request with file and upload_details as body
169
315
  resp = await self._http_post(url=url, data=data, files=files, presigned_url_post=True)
170
316
  self.logger.debug(
@@ -275,38 +421,55 @@ class PangeaRequestAsync(PangeaRequestBase):
275
421
  attached_files = await self._get_attached_files(multipart_reader)
276
422
  return MultipartResponse(pangea_json, attached_files) # type: ignore[arg-type]
277
423
 
424
+ async def _http_delete(
425
+ self,
426
+ url: str,
427
+ *,
428
+ headers: Mapping[str, str | bytes | None] = {},
429
+ ) -> aiohttp.ClientResponse:
430
+ return await self.session.delete(url, headers=headers)
431
+
278
432
  async def _http_post(
279
433
  self,
280
434
  url: str,
281
- headers: Dict = {},
282
- data: Union[str, Dict] = {},
283
- files: Optional[List[Tuple]] = [],
435
+ headers: Mapping[str, str] = {},
436
+ data: str | dict[str, Any] | None = None,
437
+ files: _Files | None = None,
284
438
  presigned_url_post: bool = False,
285
439
  ) -> aiohttp.ClientResponse:
440
+ if data is None:
441
+ data = {}
442
+
286
443
  if files:
287
444
  form = FormData()
288
445
  if presigned_url_post:
289
- for k, v in data.items(): # type: ignore[union-attr]
446
+ assert isinstance(data, dict)
447
+ assert isinstance(files, list)
448
+ for k, v in data.items():
290
449
  form.add_field(k, v)
291
- for name, value in files:
450
+ for _name, value in files:
292
451
  form.add_field("file", value[1], filename=value[0], content_type=value[2])
293
452
  else:
294
- data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
453
+ assert isinstance(files, list)
454
+ data_send: str | FormData = (
455
+ json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
456
+ )
295
457
  form.add_field("request", data_send, content_type="application/json")
296
458
  for name, value in files:
297
459
  form.add_field(name, value[1], filename=value[0], content_type=value[2])
298
460
 
299
- data_send = form # type: ignore[assignment]
461
+ data_send = form
300
462
  else:
301
463
  data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
302
464
 
465
+ assert isinstance(self.session, aiohttp.ClientSession)
303
466
  return await self.session.post(url, headers=headers, data=data_send)
304
467
 
305
468
  async def _http_put(
306
469
  self,
307
470
  url: str,
308
471
  files: Sequence[Tuple],
309
- headers: Dict = {},
472
+ headers: Mapping[str, str] = {},
310
473
  ) -> aiohttp.ClientResponse:
311
474
  self.logger.debug(
312
475
  json.dumps({"service": self.service, "action": "http_put", "url": url}, default=default_encoder)
@@ -318,8 +481,8 @@ class PangeaRequestAsync(PangeaRequestBase):
318
481
  self,
319
482
  endpoint: str,
320
483
  result_class: Type[PangeaResponseResult],
321
- data: Union[str, Dict] = {},
322
- files: List[Tuple] = [],
484
+ data: Union[str, Mapping[str, Any]] = {},
485
+ files: Sequence[Tuple] = [],
323
486
  ):
324
487
  if len(files) == 0:
325
488
  raise AttributeError("files attribute should have at least 1 file")
@@ -343,7 +506,7 @@ class PangeaRequestAsync(PangeaRequestBase):
343
506
  self,
344
507
  endpoint: str,
345
508
  result_class: Type[PangeaResponseResult],
346
- data: Union[str, Dict] = {},
509
+ data: Union[str, Mapping[str, Any]] = {},
347
510
  ) -> PangeaResponse:
348
511
  # Send request
349
512
  try:
@@ -394,7 +557,7 @@ class PangeaRequestAsync(PangeaRequestBase):
394
557
  {"service": self.service, "action": "poll_presigned_url", "step": "exit", "cause": {str(e)}}
395
558
  )
396
559
  )
397
- 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
398
561
 
399
562
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_presigned_url", "step": "exit"}))
400
563
 
@@ -426,6 +589,7 @@ class PangeaRequestAsync(PangeaRequestBase):
426
589
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_retry", "step": "exit"}))
427
590
  return self._check_response(response)
428
591
 
592
+ @override
429
593
  def _init_session(self) -> aiohttp.ClientSession:
430
594
  # retry_config = Retry(
431
595
  # 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,6 +7,7 @@ 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
10
+ from .management import ManagementAsync
8
11
  from .prompt_guard import PromptGuardAsync
9
12
  from .redact import RedactAsync
10
13
  from .sanitize import SanitizeAsync
@@ -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 LogFields, Overrides, TextGuardResult
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
+ )