pangea-sdk 6.0.0__py3-none-any.whl → 6.2.0b1__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 +1 -1
- pangea/asyncio/request.py +153 -19
- pangea/asyncio/services/__init__.py +1 -0
- pangea/asyncio/services/audit.py +300 -1
- pangea/asyncio/services/authn.py +171 -14
- pangea/asyncio/services/authz.py +28 -28
- pangea/asyncio/services/management.py +576 -0
- pangea/asyncio/services/redact.py +265 -4
- pangea/request.py +155 -19
- pangea/services/__init__.py +1 -0
- pangea/services/audit/audit.py +301 -1
- pangea/services/audit/models.py +275 -0
- pangea/services/authn/authn.py +177 -18
- pangea/services/authn/models.py +94 -0
- pangea/services/authz.py +65 -30
- pangea/services/management.py +720 -0
- pangea/services/redact.py +473 -7
- {pangea_sdk-6.0.0.dist-info → pangea_sdk-6.2.0b1.dist-info}/METADATA +3 -3
- {pangea_sdk-6.0.0.dist-info → pangea_sdk-6.2.0b1.dist-info}/RECORD +20 -18
- {pangea_sdk-6.0.0.dist-info → pangea_sdk-6.2.0b1.dist-info}/WHEEL +0 -0
@@ -2,12 +2,15 @@
|
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from
|
5
|
+
from collections.abc import Mapping, Sequence
|
6
|
+
from typing import Dict, List, Literal, Optional, Union, cast, overload
|
7
|
+
|
8
|
+
from pydantic import TypeAdapter
|
6
9
|
|
7
10
|
import pangea.services.redact as m
|
8
11
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
9
12
|
from pangea.config import PangeaConfig
|
10
|
-
from pangea.response import PangeaResponse
|
13
|
+
from pangea.response import PangeaResponse, PangeaResponseResult
|
11
14
|
|
12
15
|
|
13
16
|
class RedactAsync(ServiceBaseAsync):
|
@@ -64,7 +67,7 @@ class RedactAsync(ServiceBaseAsync):
|
|
64
67
|
rules: Optional[List[str]] = None,
|
65
68
|
rulesets: Optional[List[str]] = None,
|
66
69
|
return_result: Optional[bool] = None,
|
67
|
-
redaction_method_overrides:
|
70
|
+
redaction_method_overrides: Mapping[str, m.RedactionMethodOverrides] | None = None,
|
68
71
|
llm_request: Optional[bool] = None,
|
69
72
|
vault_parameters: Optional[m.VaultParameters] = None,
|
70
73
|
) -> PangeaResponse[m.RedactResult]:
|
@@ -119,7 +122,7 @@ class RedactAsync(ServiceBaseAsync):
|
|
119
122
|
rules: Optional[List[str]] = None,
|
120
123
|
rulesets: Optional[List[str]] = None,
|
121
124
|
return_result: Optional[bool] = None,
|
122
|
-
redaction_method_overrides:
|
125
|
+
redaction_method_overrides: Mapping[str, m.RedactionMethodOverrides] | None = None,
|
123
126
|
llm_request: bool | None = None,
|
124
127
|
vault_parameters: m.VaultParameters | None = None,
|
125
128
|
) -> PangeaResponse[m.StructuredResult]:
|
@@ -200,3 +203,261 @@ class RedactAsync(ServiceBaseAsync):
|
|
200
203
|
"""
|
201
204
|
input = m.UnredactRequest(redacted_data=redacted_data, fpe_context=fpe_context)
|
202
205
|
return await self.request.post("v1/unredact", m.UnredactResult, data=input.model_dump(exclude_none=True))
|
206
|
+
|
207
|
+
async def get_service_config(self, config_id: str) -> PangeaResponse[m.ServiceConfigResult]:
|
208
|
+
"""
|
209
|
+
Get a service config.
|
210
|
+
|
211
|
+
|
212
|
+
OperationId: redact_post_v1beta_config
|
213
|
+
"""
|
214
|
+
response = await self.request.post("v1beta/config", PangeaResponseResult, data={"id": config_id})
|
215
|
+
response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
|
216
|
+
return cast(PangeaResponse[m.ServiceConfigResult], response)
|
217
|
+
|
218
|
+
@overload
|
219
|
+
async def create_service_config(
|
220
|
+
self,
|
221
|
+
name: str,
|
222
|
+
*,
|
223
|
+
version: Literal["1.0.0"],
|
224
|
+
enabled_rules: Sequence[str] | None = None,
|
225
|
+
redactions: Mapping[str, m.Redaction] | None = None,
|
226
|
+
vault_service_config_id: str | None = None,
|
227
|
+
salt_vault_secret_id: str | None = None,
|
228
|
+
rules: Mapping[str, m.RuleV1] | None = None,
|
229
|
+
rulesets: Mapping[str, m.RulesetV1] | None = None,
|
230
|
+
supported_languages: Sequence[Literal["en"]] | None = None,
|
231
|
+
) -> PangeaResponse[m.ServiceConfigResult]:
|
232
|
+
"""
|
233
|
+
Create a v1.0.0 service config.
|
234
|
+
|
235
|
+
OperationId: redact_post_v1beta_config_create
|
236
|
+
|
237
|
+
Args:
|
238
|
+
vault_service_config_id: Service config used to create the secret
|
239
|
+
salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
|
240
|
+
"""
|
241
|
+
|
242
|
+
@overload
|
243
|
+
async def create_service_config(
|
244
|
+
self,
|
245
|
+
name: str,
|
246
|
+
*,
|
247
|
+
version: Literal["2.0.0"] | None = None,
|
248
|
+
enabled_rules: Sequence[str] | None = None,
|
249
|
+
enforce_enabled_rules: bool | None = None,
|
250
|
+
redactions: Mapping[str, m.Redaction] | None = None,
|
251
|
+
vault_service_config_id: str | None = None,
|
252
|
+
salt_vault_secret_id: str | None = None,
|
253
|
+
fpe_vault_secret_id: str | None = None,
|
254
|
+
rules: Mapping[str, m.RuleV2] | None = None,
|
255
|
+
rulesets: Mapping[str, m.RulesetV2] | None = None,
|
256
|
+
supported_languages: Sequence[Literal["en"]] | None = None,
|
257
|
+
) -> PangeaResponse[m.ServiceConfigResult]:
|
258
|
+
"""
|
259
|
+
Create a v2.0.0 service config.
|
260
|
+
|
261
|
+
OperationId: redact_post_v1beta_config_create
|
262
|
+
|
263
|
+
Args:
|
264
|
+
enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
|
265
|
+
vault_service_config_id: Service config used to create the secret
|
266
|
+
salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
|
267
|
+
fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
|
268
|
+
"""
|
269
|
+
|
270
|
+
async def create_service_config(
|
271
|
+
self,
|
272
|
+
name: str,
|
273
|
+
*,
|
274
|
+
version: Literal["1.0.0", "2.0.0"] | None = None,
|
275
|
+
enabled_rules: Sequence[str] | None = None,
|
276
|
+
enforce_enabled_rules: bool | None = None,
|
277
|
+
fpe_vault_secret_id: str | None = None,
|
278
|
+
redactions: Mapping[str, m.Redaction] | None = None,
|
279
|
+
rules: Mapping[str, m.RuleV1 | m.RuleV2] | None = None,
|
280
|
+
rulesets: Mapping[str, m.RulesetV1 | m.RulesetV2] | None = None,
|
281
|
+
salt_vault_secret_id: str | None = None,
|
282
|
+
supported_languages: Sequence[Literal["en"]] | None = None,
|
283
|
+
vault_service_config_id: str | None = None,
|
284
|
+
) -> PangeaResponse[m.ServiceConfigResult]:
|
285
|
+
"""
|
286
|
+
Create a service config.
|
287
|
+
|
288
|
+
OperationId: redact_post_v1beta_config_create
|
289
|
+
|
290
|
+
Args:
|
291
|
+
enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
|
292
|
+
fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
|
293
|
+
salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
|
294
|
+
vault_service_config_id: Service config used to create the secret
|
295
|
+
"""
|
296
|
+
|
297
|
+
response = await self.request.post(
|
298
|
+
"v1beta/config/create",
|
299
|
+
PangeaResponseResult,
|
300
|
+
data={
|
301
|
+
"name": name,
|
302
|
+
"version": version,
|
303
|
+
"enabled_rules": enabled_rules,
|
304
|
+
"enforce_enabled_rules": enforce_enabled_rules,
|
305
|
+
"fpe_vault_secret_id": fpe_vault_secret_id,
|
306
|
+
"redactions": redactions,
|
307
|
+
"rules": rules,
|
308
|
+
"rulesets": rulesets,
|
309
|
+
"salt_vault_secret_id": salt_vault_secret_id,
|
310
|
+
"supported_languages": supported_languages,
|
311
|
+
"vault_service_config_id": vault_service_config_id,
|
312
|
+
},
|
313
|
+
)
|
314
|
+
response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
|
315
|
+
return cast(PangeaResponse[m.ServiceConfigResult], response)
|
316
|
+
|
317
|
+
@overload
|
318
|
+
async def update_service_config(
|
319
|
+
self,
|
320
|
+
config_id: str,
|
321
|
+
*,
|
322
|
+
version: Literal["1.0.0"],
|
323
|
+
name: str,
|
324
|
+
updated_at: str,
|
325
|
+
enabled_rules: Sequence[str] | None = None,
|
326
|
+
redactions: Mapping[str, m.Redaction] | None = None,
|
327
|
+
vault_service_config_id: str | None = None,
|
328
|
+
salt_vault_secret_id: str | None = None,
|
329
|
+
rules: Mapping[str, m.RuleV1] | None = None,
|
330
|
+
rulesets: Mapping[str, m.RulesetV1] | None = None,
|
331
|
+
supported_languages: Sequence[Literal["en"]] | None = None,
|
332
|
+
) -> PangeaResponse[m.ServiceConfigResult]:
|
333
|
+
"""
|
334
|
+
Update a v1.0.0 service config.
|
335
|
+
|
336
|
+
OperationId: redact_post_v1beta_config_update
|
337
|
+
|
338
|
+
Args:
|
339
|
+
vault_service_config_id: Service config used to create the secret
|
340
|
+
salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
|
341
|
+
"""
|
342
|
+
|
343
|
+
@overload
|
344
|
+
async def update_service_config(
|
345
|
+
self,
|
346
|
+
config_id: str,
|
347
|
+
*,
|
348
|
+
version: Literal["2.0.0"] | None = None,
|
349
|
+
name: str,
|
350
|
+
updated_at: str,
|
351
|
+
enabled_rules: Sequence[str] | None = None,
|
352
|
+
enforce_enabled_rules: bool | None = None,
|
353
|
+
redactions: Mapping[str, m.Redaction] | None = None,
|
354
|
+
vault_service_config_id: str | None = None,
|
355
|
+
salt_vault_secret_id: str | None = None,
|
356
|
+
fpe_vault_secret_id: str | None = None,
|
357
|
+
rules: Mapping[str, m.RuleV2] | None = None,
|
358
|
+
rulesets: Mapping[str, m.RulesetV2] | None = None,
|
359
|
+
supported_languages: Sequence[Literal["en"]] | None = None,
|
360
|
+
) -> PangeaResponse[m.ServiceConfigResult]:
|
361
|
+
"""
|
362
|
+
Update a v2.0.0 service config.
|
363
|
+
|
364
|
+
OperationId: redact_post_v1beta_config_update
|
365
|
+
|
366
|
+
Args:
|
367
|
+
enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
|
368
|
+
vault_service_config_id: Service config used to create the secret
|
369
|
+
salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
|
370
|
+
fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
|
371
|
+
"""
|
372
|
+
|
373
|
+
async def update_service_config(
|
374
|
+
self,
|
375
|
+
config_id: str,
|
376
|
+
*,
|
377
|
+
version: Literal["1.0.0", "2.0.0"] | None = None,
|
378
|
+
name: str,
|
379
|
+
updated_at: str,
|
380
|
+
enabled_rules: Sequence[str] | None = None,
|
381
|
+
enforce_enabled_rules: bool | None = None,
|
382
|
+
fpe_vault_secret_id: str | None = None,
|
383
|
+
redactions: Mapping[str, m.Redaction] | None = None,
|
384
|
+
rules: Mapping[str, m.RuleV1 | m.RuleV2] | None = None,
|
385
|
+
rulesets: Mapping[str, m.RulesetV1 | m.RulesetV2] | None = None,
|
386
|
+
salt_vault_secret_id: str | None = None,
|
387
|
+
supported_languages: Sequence[Literal["en"]] | None = None,
|
388
|
+
vault_service_config_id: str | None = None,
|
389
|
+
) -> PangeaResponse[m.ServiceConfigResult]:
|
390
|
+
"""
|
391
|
+
Update a service config.
|
392
|
+
|
393
|
+
OperationId: redact_post_v1beta_config_update
|
394
|
+
|
395
|
+
Args:
|
396
|
+
enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
|
397
|
+
fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
|
398
|
+
salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
|
399
|
+
vault_service_config_id: Service config used to create the secret
|
400
|
+
"""
|
401
|
+
|
402
|
+
response = await self.request.post(
|
403
|
+
"v1beta/config/update",
|
404
|
+
PangeaResponseResult,
|
405
|
+
data={
|
406
|
+
"id": config_id,
|
407
|
+
"updated_at": updated_at,
|
408
|
+
"name": name,
|
409
|
+
"version": version,
|
410
|
+
"enabled_rules": enabled_rules,
|
411
|
+
"enforce_enabled_rules": enforce_enabled_rules,
|
412
|
+
"fpe_vault_secret_id": fpe_vault_secret_id,
|
413
|
+
"redactions": redactions,
|
414
|
+
"rules": rules,
|
415
|
+
"rulesets": rulesets,
|
416
|
+
"salt_vault_secret_id": salt_vault_secret_id,
|
417
|
+
"supported_languages": supported_languages,
|
418
|
+
"vault_service_config_id": vault_service_config_id,
|
419
|
+
},
|
420
|
+
)
|
421
|
+
response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
|
422
|
+
return cast(PangeaResponse[m.ServiceConfigResult], response)
|
423
|
+
|
424
|
+
async def delete_service_config(self, config_id: str) -> PangeaResponse[m.ServiceConfigResult]:
|
425
|
+
"""
|
426
|
+
Delete a service config.
|
427
|
+
|
428
|
+
OperationId: redact_post_v1beta_config_delete
|
429
|
+
|
430
|
+
Args:
|
431
|
+
config_id: An ID for a service config
|
432
|
+
"""
|
433
|
+
|
434
|
+
response = await self.request.post("v1beta/config/delete", PangeaResponseResult, data={"id": config_id})
|
435
|
+
response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
|
436
|
+
return cast(PangeaResponse[m.ServiceConfigResult], response)
|
437
|
+
|
438
|
+
async def list_service_configs(
|
439
|
+
self,
|
440
|
+
*,
|
441
|
+
filter: m.ServiceConfigFilter | None = None,
|
442
|
+
last: str | None = None,
|
443
|
+
order: Literal["asc", "desc"] | None = None,
|
444
|
+
order_by: Literal["id", "created_at", "updated_at"] | None = None,
|
445
|
+
size: int | None = None,
|
446
|
+
) -> PangeaResponse[m.ServiceConfigListResult]:
|
447
|
+
"""
|
448
|
+
List service configs.
|
449
|
+
|
450
|
+
OperationId: redact_post_v1beta_config_list
|
451
|
+
|
452
|
+
Args:
|
453
|
+
last: Reflected value from a previous response to obtain the next page of results.
|
454
|
+
order: Order results asc(ending) or desc(ending).
|
455
|
+
order_by: Which field to order results by.
|
456
|
+
size: Maximum results to include in the response.
|
457
|
+
"""
|
458
|
+
|
459
|
+
return await self.request.post(
|
460
|
+
"v1beta/config/list",
|
461
|
+
m.ServiceConfigListResult,
|
462
|
+
data={"filter": filter, "last": last, "order": order, "order_by": order_by, "size": size},
|
463
|
+
)
|
pangea/request.py
CHANGED
@@ -6,10 +6,11 @@ import copy
|
|
6
6
|
import json
|
7
7
|
import logging
|
8
8
|
import time
|
9
|
-
from
|
9
|
+
from collections.abc import Iterable, Mapping
|
10
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Sequence, Tuple, Type, Union, cast, overload
|
10
11
|
|
11
12
|
import requests
|
12
|
-
from pydantic import BaseModel
|
13
|
+
from pydantic import BaseModel, TypeAdapter
|
13
14
|
from pydantic_core import to_jsonable_python
|
14
15
|
from requests.adapters import HTTPAdapter, Retry
|
15
16
|
from requests_toolbelt import MultipartDecoder # type: ignore[import-untyped]
|
@@ -200,6 +201,24 @@ class PangeaRequest(PangeaRequestBase):
|
|
200
201
|
def __del__(self) -> None:
|
201
202
|
self.session.close()
|
202
203
|
|
204
|
+
def delete(self, endpoint: str) -> None:
|
205
|
+
"""
|
206
|
+
Makes a DELETE call to a Pangea endpoint.
|
207
|
+
|
208
|
+
Args:
|
209
|
+
endpoint: The Pangea API endpoint.
|
210
|
+
"""
|
211
|
+
|
212
|
+
url = self._url(endpoint)
|
213
|
+
|
214
|
+
self.logger.debug(
|
215
|
+
json.dumps({"service": self.service, "action": "delete", "url": url}, default=default_encoder)
|
216
|
+
)
|
217
|
+
|
218
|
+
requests_response = self._http_delete(url, headers=self._headers())
|
219
|
+
self._check_http_errors(requests_response)
|
220
|
+
|
221
|
+
@overload
|
203
222
|
def post(
|
204
223
|
self,
|
205
224
|
endpoint: str,
|
@@ -208,18 +227,62 @@ class PangeaRequest(PangeaRequestBase):
|
|
208
227
|
files: Optional[List[Tuple]] = None,
|
209
228
|
poll_result: bool = True,
|
210
229
|
url: Optional[str] = None,
|
230
|
+
*,
|
231
|
+
pangea_response: Literal[True] = True,
|
211
232
|
) -> PangeaResponse[TResult]:
|
212
|
-
"""
|
233
|
+
"""
|
234
|
+
Makes the POST call to a Pangea Service endpoint.
|
213
235
|
|
214
236
|
Args:
|
215
|
-
endpoint
|
216
|
-
data
|
237
|
+
endpoint: The Pangea Service API endpoint.
|
238
|
+
data: The POST body payload object
|
217
239
|
|
218
240
|
Returns:
|
219
241
|
PangeaResponse which contains the response in its entirety and
|
220
242
|
various properties to retrieve individual fields
|
221
243
|
"""
|
222
244
|
|
245
|
+
@overload
|
246
|
+
def post(
|
247
|
+
self,
|
248
|
+
endpoint: str,
|
249
|
+
result_class: Type[TResult],
|
250
|
+
data: str | BaseModel | dict[str, Any] | None = None,
|
251
|
+
files: Optional[List[Tuple]] = None,
|
252
|
+
poll_result: bool = True,
|
253
|
+
url: Optional[str] = None,
|
254
|
+
*,
|
255
|
+
pangea_response: Literal[False],
|
256
|
+
) -> TResult:
|
257
|
+
"""
|
258
|
+
Makes the POST call to a Pangea Service endpoint.
|
259
|
+
|
260
|
+
Args:
|
261
|
+
endpoint: The Pangea Service API endpoint.
|
262
|
+
data: The POST body payload object
|
263
|
+
"""
|
264
|
+
|
265
|
+
def post(
|
266
|
+
self,
|
267
|
+
endpoint: str,
|
268
|
+
result_class: Type[TResult],
|
269
|
+
data: str | BaseModel | dict[str, Any] | None = None,
|
270
|
+
files: Optional[List[Tuple]] = None,
|
271
|
+
poll_result: bool = True,
|
272
|
+
url: Optional[str] = None,
|
273
|
+
*,
|
274
|
+
pangea_response: bool = True,
|
275
|
+
) -> PangeaResponse[TResult] | TResult:
|
276
|
+
"""
|
277
|
+
Makes the POST call to a Pangea Service endpoint.
|
278
|
+
|
279
|
+
Args:
|
280
|
+
endpoint: The Pangea Service API endpoint.
|
281
|
+
data: The POST body payload object
|
282
|
+
pangea_response: Whether or not the response body follows Pangea's
|
283
|
+
standard response schema
|
284
|
+
"""
|
285
|
+
|
223
286
|
if isinstance(data, BaseModel):
|
224
287
|
data = data.model_dump(exclude_none=True)
|
225
288
|
|
@@ -256,9 +319,13 @@ class PangeaRequest(PangeaRequestBase):
|
|
256
319
|
|
257
320
|
self._check_http_errors(requests_response)
|
258
321
|
|
322
|
+
if not pangea_response:
|
323
|
+
type_adapter = TypeAdapter(result_class)
|
324
|
+
return type_adapter.validate_python(requests_response.json())
|
325
|
+
|
259
326
|
if "multipart/form-data" in requests_response.headers.get("content-type", ""):
|
260
327
|
multipart_response = self._process_multipart_response(requests_response)
|
261
|
-
|
328
|
+
pangea_response_obj: PangeaResponse = PangeaResponse(
|
262
329
|
requests_response,
|
263
330
|
result_class=result_class,
|
264
331
|
json=multipart_response.pangea_json,
|
@@ -271,14 +338,14 @@ class PangeaRequest(PangeaRequestBase):
|
|
271
338
|
json.dumps({"service": self.service, "action": "post", "url": url, "response": json_resp})
|
272
339
|
)
|
273
340
|
|
274
|
-
|
341
|
+
pangea_response_obj = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
|
275
342
|
except requests.exceptions.JSONDecodeError as e:
|
276
343
|
raise pe.PangeaException(f"Failed to decode json response. {e}. Body: {requests_response.text}")
|
277
344
|
|
278
345
|
if poll_result:
|
279
|
-
|
346
|
+
pangea_response_obj = self._handle_queued_result(pangea_response_obj)
|
280
347
|
|
281
|
-
return self._check_response(
|
348
|
+
return self._check_response(pangea_response_obj)
|
282
349
|
|
283
350
|
def _get_pangea_json(self, decoder: MultipartDecoder) -> Optional[Dict]:
|
284
351
|
# Iterate through parts
|
@@ -321,10 +388,18 @@ class PangeaRequest(PangeaRequestBase):
|
|
321
388
|
if resp.status_code == 503:
|
322
389
|
raise pe.ServiceTemporarilyUnavailable(resp.json())
|
323
390
|
|
391
|
+
def _http_delete(
|
392
|
+
self,
|
393
|
+
url: str,
|
394
|
+
*,
|
395
|
+
headers: Mapping[str, str | bytes | None] = {},
|
396
|
+
) -> requests.Response:
|
397
|
+
return self.session.delete(url, headers=headers)
|
398
|
+
|
324
399
|
def _http_post(
|
325
400
|
self,
|
326
401
|
url: str,
|
327
|
-
headers:
|
402
|
+
headers: Mapping[str, str | bytes | None] = {},
|
328
403
|
data: Union[str, Dict] = {},
|
329
404
|
files: Optional[List[Tuple]] = None,
|
330
405
|
multipart_post: bool = True,
|
@@ -371,37 +446,98 @@ class PangeaRequest(PangeaRequestBase):
|
|
371
446
|
|
372
447
|
return response
|
373
448
|
|
374
|
-
|
375
|
-
|
449
|
+
@overload
|
450
|
+
def get(
|
451
|
+
self,
|
452
|
+
path: str,
|
453
|
+
result_class: Type[TResult],
|
454
|
+
check_response: bool = True,
|
455
|
+
*,
|
456
|
+
params: (
|
457
|
+
Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
|
458
|
+
| None
|
459
|
+
) = None,
|
460
|
+
pangea_response: Literal[True] = True,
|
461
|
+
) -> PangeaResponse[TResult]:
|
462
|
+
"""
|
463
|
+
Makes the GET call to a Pangea Service endpoint.
|
376
464
|
|
377
465
|
Args:
|
378
|
-
|
379
|
-
|
466
|
+
path: Additional URL path
|
467
|
+
params: Dictionary of querystring data to attach to the request
|
380
468
|
|
381
469
|
Returns:
|
382
470
|
PangeaResponse which contains the response in its entirety and
|
383
471
|
various properties to retrieve individual fields
|
384
472
|
"""
|
385
473
|
|
474
|
+
@overload
|
475
|
+
def get(
|
476
|
+
self,
|
477
|
+
path: str,
|
478
|
+
result_class: Type[TResult],
|
479
|
+
check_response: bool = True,
|
480
|
+
*,
|
481
|
+
params: (
|
482
|
+
Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
|
483
|
+
| None
|
484
|
+
) = None,
|
485
|
+
pangea_response: Literal[False] = False,
|
486
|
+
) -> TResult:
|
487
|
+
"""
|
488
|
+
Makes the GET call to a Pangea Service endpoint.
|
489
|
+
|
490
|
+
Args:
|
491
|
+
path: Additional URL path
|
492
|
+
params: Dictionary of querystring data to attach to the request
|
493
|
+
"""
|
494
|
+
|
495
|
+
def get(
|
496
|
+
self,
|
497
|
+
path: str,
|
498
|
+
result_class: Type[TResult],
|
499
|
+
check_response: bool = True,
|
500
|
+
*,
|
501
|
+
params: (
|
502
|
+
Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
|
503
|
+
| None
|
504
|
+
) = None,
|
505
|
+
pangea_response: bool = True,
|
506
|
+
) -> PangeaResponse[TResult] | TResult:
|
507
|
+
"""
|
508
|
+
Makes the GET call to a Pangea Service endpoint.
|
509
|
+
|
510
|
+
Args:
|
511
|
+
path: Additional URL path
|
512
|
+
params: Dictionary of querystring data to attach to the request
|
513
|
+
pangea_response: Whether or not the response body follows Pangea's
|
514
|
+
standard response schema
|
515
|
+
"""
|
516
|
+
|
386
517
|
url = self._url(path)
|
387
518
|
self.logger.debug(json.dumps({"service": self.service, "action": "get", "url": url}))
|
388
|
-
requests_response = self.session.get(url, headers=self._headers())
|
519
|
+
requests_response = self.session.get(url, params=params, headers=self._headers())
|
389
520
|
self._check_http_errors(requests_response)
|
390
|
-
|
521
|
+
|
522
|
+
if not pangea_response:
|
523
|
+
type_adapter = TypeAdapter(result_class)
|
524
|
+
return type_adapter.validate_python(requests_response.json())
|
525
|
+
|
526
|
+
pangea_response_obj: PangeaResponse = PangeaResponse(
|
391
527
|
requests_response, result_class=result_class, json=requests_response.json()
|
392
528
|
)
|
393
529
|
|
394
530
|
self.logger.debug(
|
395
531
|
json.dumps(
|
396
|
-
{"service": self.service, "action": "get", "url": url, "response":
|
532
|
+
{"service": self.service, "action": "get", "url": url, "response": pangea_response_obj.json},
|
397
533
|
default=default_encoder,
|
398
534
|
)
|
399
535
|
)
|
400
536
|
|
401
537
|
if check_response is False:
|
402
|
-
return
|
538
|
+
return pangea_response_obj
|
403
539
|
|
404
|
-
return self._check_response(
|
540
|
+
return self._check_response(pangea_response_obj)
|
405
541
|
|
406
542
|
def download_file(self, url: str, filename: str | None = None) -> AttachedFile:
|
407
543
|
"""
|
pangea/services/__init__.py
CHANGED
@@ -5,6 +5,7 @@ from .authz import AuthZ
|
|
5
5
|
from .embargo import Embargo
|
6
6
|
from .file_scan import FileScan
|
7
7
|
from .intel import DomainIntel, FileIntel, IpIntel, UrlIntel, UserIntel
|
8
|
+
from .management import Management
|
8
9
|
from .prompt_guard import PromptGuard
|
9
10
|
from .redact import Redact
|
10
11
|
from .sanitize import Sanitize
|