pangea-sdk 5.2.0__py3-none-any.whl → 5.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 CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "5.2.0"
1
+ __version__ = "5.2.0beta1"
2
2
 
3
3
  from pangea.asyncio.request import PangeaRequestAsync
4
4
  from pangea.config import PangeaConfig
pangea/asyncio/request.py CHANGED
@@ -5,11 +5,12 @@ from __future__ import annotations
5
5
  import asyncio
6
6
  import json
7
7
  import time
8
- from typing import Any, Dict, List, Optional, Sequence, Tuple, Type, Union
8
+ from typing import Dict, List, Optional, Sequence, Tuple, Type, Union, cast
9
9
 
10
10
  import aiohttp
11
11
  from aiohttp import FormData
12
12
  from pydantic import BaseModel
13
+ from pydantic_core import to_jsonable_python
13
14
  from typing_extensions import Any, TypeVar
14
15
 
15
16
  import pangea.exceptions as pe
@@ -55,17 +56,20 @@ class PangeaRequestAsync(PangeaRequestBase):
55
56
  if data is None:
56
57
  data = {}
57
58
 
59
+ # Normalize.
60
+ data = cast(dict[str, Any], to_jsonable_python(data))
61
+
58
62
  if url is None:
59
63
  url = self._url(endpoint)
60
64
 
61
65
  # Set config ID if available
62
- if self.config_id and data.get("config_id", None) is None: # type: ignore[union-attr]
63
- data["config_id"] = self.config_id # type: ignore[index]
66
+ if self.config_id and data.get("config_id", None) is None:
67
+ data["config_id"] = self.config_id
64
68
 
65
69
  self.logger.debug(
66
70
  json.dumps({"service": self.service, "action": "post", "url": url, "data": data}, default=default_encoder)
67
71
  )
68
- transfer_method = data.get("transfer_method", None) # type: ignore[union-attr]
72
+ transfer_method = data.get("transfer_method", None)
69
73
 
70
74
  if files and type(data) is dict and (transfer_method == TransferMethod.POST_URL.value):
71
75
  requests_response = await self._full_post_presigned_url(
@@ -182,20 +186,7 @@ class PangeaRequestAsync(PangeaRequestBase):
182
186
  if resp.status < 200 or resp.status >= 300:
183
187
  raise pe.PresignedUploadError(f"presigned PUT failure: {resp.status}", await resp.text())
184
188
 
185
- async def download_file(self, url: str, filename: str | None = None) -> AttachedFile:
186
- """
187
- Download file
188
-
189
- Download a file from the specified URL and save it with the given
190
- filename.
191
-
192
- Args:
193
- url: URL of the file to download
194
- filename: Name to save the downloaded file as. If not provided, the
195
- filename will be determined from the Content-Disposition header or
196
- the URL.
197
- """
198
-
189
+ async def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile:
199
190
  self.logger.debug(
200
191
  json.dumps(
201
192
  {
@@ -174,16 +174,14 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
174
174
  verbose: Optional[bool] = None,
175
175
  ) -> PangeaResponse[LogResult]:
176
176
  """
177
- Log an event
177
+ Log an entry
178
178
 
179
179
  Create a log entry in the Secure Audit Log.
180
-
181
180
  Args:
182
181
  event (dict[str, Any]): event to be logged
183
182
  verify (bool, optional): True to verify logs consistency after response.
184
183
  sign_local (bool, optional): True to sign event with local key.
185
184
  verbose (bool, optional): True to get a more verbose response.
186
-
187
185
  Raises:
188
186
  AuditException: If an audit based api exception happens
189
187
  PangeaAPIException: If an API Error happens
@@ -194,7 +192,13 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
194
192
  Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#log-an-entry).
195
193
 
196
194
  Examples:
197
- response = await audit.log_event({"message": "hello world"}, verbose=True)
195
+ try:
196
+ log_response = audit.log({"message"="Hello world"}, verbose=False)
197
+ print(f"Response. Hash: {log_response.result.hash}")
198
+ except pe.PangeaAPIException as e:
199
+ print(f"Request Error: {e.response.summary}")
200
+ for err in e.errors:
201
+ print(f"\\t{err.detail} \\n")
198
202
  """
199
203
 
200
204
  input = self._get_log_request(event, sign_local=sign_local, verify=verify, verbose=verbose)
@@ -628,9 +632,9 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
628
632
  if pub_root is not None:
629
633
  self.pub_roots[tree_size] = pub_root
630
634
 
631
- await self._fix_consistency_proofs(tree_sizes)
635
+ await self.fix_consistency_proofs(tree_sizes)
632
636
 
633
- async def _fix_consistency_proofs(self, tree_sizes: Iterable[int]) -> None:
637
+ async def fix_consistency_proofs(self, tree_sizes: Iterable[int]):
634
638
  # on very rare occasions, the consistency proof in Arweave may be wrong
635
639
  # override it with the proof from pangea (not the root hash, just the proof)
636
640
  for tree_size in tree_sizes:
@@ -1,12 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
3
 
4
- from __future__ import annotations
5
-
6
4
  from typing import Any, Dict, List, Optional
7
5
 
8
6
  from pangea.asyncio.services.base import ServiceBaseAsync
9
- from pangea.config import PangeaConfig
10
7
  from pangea.response import PangeaResponse
11
8
  from pangea.services.authz import (
12
9
  CheckRequest,
@@ -39,8 +36,8 @@ class AuthZAsync(ServiceBaseAsync):
39
36
 
40
37
  Examples:
41
38
  import os
42
- from pangea.asyncio.services import AuthZAsync
43
39
  from pangea.config import PangeaConfig
40
+ from pangea.services import AuthZ
44
41
 
45
42
  PANGEA_TOKEN = os.getenv("PANGEA_AUTHZ_TOKEN")
46
43
 
@@ -52,25 +49,7 @@ class AuthZAsync(ServiceBaseAsync):
52
49
 
53
50
  service_name = "authz"
54
51
 
55
- def __init__(
56
- self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
57
- ) -> None:
58
- """
59
- AuthZ client
60
-
61
- Initializes a new AuthZ client.
62
-
63
- Args:
64
- token: Pangea API token.
65
- config: Configuration.
66
- logger_name: Logger name.
67
- config_id: Configuration ID.
68
-
69
- Examples:
70
- config = PangeaConfig(domain="aws.us.pangea.cloud")
71
- authz = AuthZAsync(token="pangea_token", config=config)
72
- """
73
-
52
+ def __init__(self, token: str, config=None, logger_name="pangea", config_id: Optional[str] = None):
74
53
  super().__init__(token, config, logger_name, config_id=config_id)
75
54
 
76
55
  async def tuple_create(self, tuples: List[Tuple]) -> PangeaResponse[TupleCreateResult]:
@@ -1,11 +1,8 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
3
 
5
4
  from typing import Dict, Optional, Type, Union
6
5
 
7
- from typing_extensions import override
8
-
9
6
  from pangea.asyncio.request import PangeaRequestAsync
10
7
  from pangea.exceptions import AcceptedRequestException
11
8
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
@@ -26,7 +23,6 @@ class ServiceBaseAsync(ServiceBase):
26
23
 
27
24
  return self._request
28
25
 
29
- @override
30
26
  async def poll_result( # type: ignore[override]
31
27
  self,
32
28
  exception: Optional[AcceptedRequestException] = None,
@@ -40,8 +36,7 @@ class ServiceBaseAsync(ServiceBase):
40
36
  Returns request's result that has been accepted by the server
41
37
 
42
38
  Args:
43
- exception: Exception that was previously raised by the SDK on a call
44
- that is being processed.
39
+ exception (AcceptedRequestException): Exception raise by SDK on the call that is been processed.
45
40
 
46
41
  Returns:
47
42
  PangeaResponse
@@ -63,21 +58,7 @@ class ServiceBaseAsync(ServiceBase):
63
58
  else:
64
59
  raise AttributeError("Need to set exception, response or request_id")
65
60
 
66
- @override
67
- async def download_file(self, url: str, filename: str | None = None) -> AttachedFile: # type: ignore[override]
68
- """
69
- Download file
70
-
71
- Download a file from the specified URL and save it with the given
72
- filename.
73
-
74
- Args:
75
- url: URL of the file to download
76
- filename: Name to save the downloaded file as. If not provided, the
77
- filename will be determined from the Content-Disposition header or
78
- the URL.
79
- """
80
-
61
+ async def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile: # type: ignore[override]
81
62
  return await self.request.download_file(url=url, filename=filename)
82
63
 
83
64
  async def close(self):
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+
3
+ from pangea.asyncio.services.base import ServiceBaseAsync
4
+ from pangea.response import PangeaResponse, PangeaResponseResult
5
+ from pangea.services.data_guard import TextGuardResult
6
+
7
+
8
+ class DataGuard(ServiceBaseAsync):
9
+ """Data Guard service client.
10
+
11
+ Provides methods to interact with Pangea's Data Guard service.
12
+ """
13
+
14
+ service_name = "data-guard"
15
+
16
+ async def guard_text(
17
+ self,
18
+ text: str,
19
+ *,
20
+ recipe: str = "pangea_prompt_guard",
21
+ debug: bool = False,
22
+ ) -> PangeaResponse[TextGuardResult]:
23
+ """
24
+ Text guard (Beta)
25
+
26
+ Guard text.
27
+
28
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
29
+
30
+ OperationId: data_guard_post_v1_text_guard
31
+
32
+ Args:
33
+ text: Text.
34
+ recipe: Recipe.
35
+ debug: Debug.
36
+
37
+ Examples:
38
+ response = await data_guard.guard_text("text")
39
+ """
40
+
41
+ return await self.request.post(
42
+ "v1/text/guard", TextGuardResult, data={"text": text, "recipe": recipe, "debug": debug}
43
+ )
44
+
45
+ async def guard_file(
46
+ self,
47
+ file_url: str,
48
+ ) -> PangeaResponse[PangeaResponseResult]:
49
+ """
50
+ File guard (Beta)
51
+
52
+ Guard a file URL.
53
+
54
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
55
+
56
+ OperationId: data_guard_post_v1_file_guard
57
+
58
+ Args:
59
+ file_url: File URL.
60
+
61
+ Examples:
62
+ response = await data_guard.guard_file("https://example.org/file.txt")
63
+ """
64
+
65
+ return await self.request.post("v1/file/guard", PangeaResponseResult, data={"file_url": file_url})
@@ -790,7 +790,6 @@ class UserIntelAsync(ServiceBaseAsync):
790
790
  verbose: Optional[bool] = None,
791
791
  raw: Optional[bool] = None,
792
792
  provider: Optional[str] = None,
793
- cursor: Optional[str] = None,
794
793
  ) -> PangeaResponse[m.UserBreachedResult]:
795
794
  """
796
795
  Look up breached users
@@ -809,7 +808,6 @@ class UserIntelAsync(ServiceBaseAsync):
809
808
  verbose (bool, optional): Echo the API parameters in the response
810
809
  raw (bool, optional): Include raw data from this provider
811
810
  provider (str, optional): Use reputation data from this provider: "crowdstrike"
812
- cursor (str, optional): A token given in the raw response from SpyCloud. Post this back to paginate results
813
811
 
814
812
  Raises:
815
813
  PangeaAPIException: If an API Error happens
@@ -837,7 +835,6 @@ class UserIntelAsync(ServiceBaseAsync):
837
835
  end=end,
838
836
  verbose=verbose,
839
837
  raw=raw,
840
- cursor=cursor,
841
838
  )
842
839
  return await self.request.post(
843
840
  "v1/user/breached", m.UserBreachedResult, data=input.model_dump(exclude_none=True)
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from pangea.asyncio.services.base import ServiceBaseAsync
6
+ from pangea.services.prompt_guard import GuardResult, Message
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Iterable
10
+
11
+ from pangea.response import PangeaResponse
12
+
13
+
14
+ class PromptGuard(ServiceBaseAsync):
15
+ """Prompt Guard service client.
16
+
17
+ Provides methods to interact with Pangea's Prompt Guard service.
18
+ """
19
+
20
+ service_name = "prompt-guard"
21
+
22
+ async def guard(self, messages: Iterable[Message]) -> PangeaResponse[GuardResult]:
23
+ """
24
+ Guard (Beta)
25
+
26
+ Guard messages.
27
+
28
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
29
+
30
+ OperationId: prompt_guard_post_v1_guard
31
+
32
+ Args:
33
+ messages: Messages..
34
+
35
+ Examples:
36
+ response = await prompt_guard.guard([Message(role="user", content="hello world")])
37
+ """
38
+
39
+ return await self.request.post("v1/guard", GuardResult, data={"messages": messages})
@@ -1,13 +1,10 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
-
5
3
  import io
6
4
  from typing import List, Optional, Tuple
7
5
 
8
6
  import pangea.services.sanitize as m
9
7
  from pangea.asyncio.services.base import ServiceBaseAsync
10
- from pangea.config import PangeaConfig
11
8
  from pangea.response import PangeaResponse, TransferMethod
12
9
  from pangea.utils import FileUploadParams, get_file_upload_params
13
10
 
@@ -19,38 +16,17 @@ class SanitizeAsync(ServiceBaseAsync):
19
16
  import os
20
17
 
21
18
  # Pangea SDK
22
- from pangea.asyncio.services import SanitizeAsync
23
19
  from pangea.config import PangeaConfig
20
+ from pangea.asyncio.services import Sanitize
24
21
 
25
22
  PANGEA_SANITIZE_TOKEN = os.getenv("PANGEA_SANITIZE_TOKEN")
26
23
  config = PangeaConfig(domain="pangea.cloud")
27
24
 
28
- sanitize = SanitizeAsync(token=PANGEA_SANITIZE_TOKEN, config=config)
25
+ sanitize = Sanitize(token=PANGEA_SANITIZE_TOKEN, config=config)
29
26
  """
30
27
 
31
28
  service_name = "sanitize"
32
29
 
33
- def __init__(
34
- self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
35
- ) -> None:
36
- """
37
- Sanitize client
38
-
39
- Initializes a new Sanitize client.
40
-
41
- Args:
42
- token: Pangea API token.
43
- config: Configuration.
44
- logger_name: Logger name.
45
- config_id: Configuration ID.
46
-
47
- Examples:
48
- config = PangeaConfig(domain="aws.us.pangea.cloud")
49
- authz = SanitizeAsync(token="pangea_token", config=config)
50
- """
51
-
52
- super().__init__(token, config, logger_name, config_id=config_id)
53
-
54
30
  async def sanitize(
55
31
  self,
56
32
  transfer_method: TransferMethod = TransferMethod.POST_URL,
@@ -7,38 +7,16 @@ from typing import Dict, List, Optional, Tuple, Union
7
7
 
8
8
  import pangea.services.share.share as m
9
9
  from pangea.asyncio.services.base import ServiceBaseAsync
10
- from pangea.config import PangeaConfig
11
10
  from pangea.response import PangeaResponse, TransferMethod
12
11
  from pangea.services.share.file_format import FileFormat
13
12
  from pangea.utils import get_file_size, get_file_upload_params
14
13
 
15
14
 
16
15
  class ShareAsync(ServiceBaseAsync):
17
- """Secure Share service client."""
16
+ """Share service client."""
18
17
 
19
18
  service_name = "share"
20
19
 
21
- def __init__(
22
- self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
23
- ) -> None:
24
- """
25
- Secure Share client
26
-
27
- Initializes a new Secure Share client.
28
-
29
- Args:
30
- token: Pangea API token.
31
- config: Configuration.
32
- logger_name: Logger name.
33
- config_id: Configuration ID.
34
-
35
- Examples:
36
- config = PangeaConfig(domain="aws.us.pangea.cloud")
37
- authz = ShareAsync(token="pangea_token", config=config)
38
- """
39
-
40
- super().__init__(token, config, logger_name, config_id=config_id)
41
-
42
20
  async def buckets(self) -> PangeaResponse[m.BucketsResult]:
43
21
  """
44
22
  Buckets
pangea/deep_verify.py CHANGED
@@ -263,14 +263,8 @@ def main():
263
263
  audit = init_audit(args.token, args.domain)
264
264
  errors = deep_verify(audit, args.file)
265
265
 
266
- print("\n\nWarnings:")
267
- val = errors["not_persisted"]
268
- print(f"\tnot_persisted: {val}")
269
-
270
- print("\nTotal errors:")
266
+ print("\n\nTotal errors:")
271
267
  for key, val in errors.items():
272
- if key == "not_persisted":
273
- continue
274
268
  print(f"\t{key.title()}: {val}")
275
269
  print()
276
270
 
pangea/dump_audit.py CHANGED
@@ -63,12 +63,11 @@ def dump_before(audit: Audit, output: io.TextIOWrapper, start: datetime) -> int:
63
63
  cnt = 0
64
64
  if search_res.result and search_res.result.count > 0:
65
65
  leaf_index = search_res.result.events[0].leaf_index
66
- if leaf_index is not None:
67
- for row in reversed(search_res.result.events):
68
- if row.leaf_index != leaf_index:
69
- break
70
- dump_event(output, row, search_res)
71
- cnt += 1
66
+ for row in reversed(search_res.result.events):
67
+ if row.leaf_index != leaf_index:
68
+ break
69
+ dump_event(output, row, search_res)
70
+ cnt += 1
72
71
  print(f"Dumping before... {cnt} events")
73
72
  return cnt
74
73
 
@@ -90,7 +89,7 @@ def dump_after(audit: Audit, output: io.TextIOWrapper, start: datetime, last_eve
90
89
  cnt = 0
91
90
  if search_res.result and search_res.result.count > 0:
92
91
  leaf_index = search_res.result.events[0].leaf_index
93
- if leaf_index is not None and leaf_index == last_leaf_index:
92
+ if leaf_index == last_leaf_index:
94
93
  start_idx: int = 1 if last_event_hash == search_res.result.events[0].hash else 0
95
94
  for row in search_res.result.events[start_idx:]:
96
95
  if row.leaf_index != leaf_index:
@@ -125,7 +124,7 @@ def dump_page(
125
124
  msg = f"Dumping... {search_res.result.count} events"
126
125
 
127
126
  if search_res.result.count <= 1:
128
- return end, 0, True, "", 0
127
+ return end, 0 # type: ignore[return-value]
129
128
 
130
129
  offset = 0
131
130
  result_id = search_res.result.id
pangea/request.py CHANGED
@@ -6,12 +6,13 @@ import copy
6
6
  import json
7
7
  import logging
8
8
  import time
9
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Tuple, Type, Union
9
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Tuple, Type, Union, cast
10
10
 
11
11
  import requests
12
12
  from pydantic import BaseModel
13
+ from pydantic_core import to_jsonable_python
13
14
  from requests.adapters import HTTPAdapter, Retry
14
- from requests_toolbelt import MultipartDecoder # type: ignore[import-untyped]
15
+ from requests_toolbelt import MultipartDecoder # type: ignore
15
16
  from typing_extensions import TypeVar
16
17
 
17
18
  import pangea
@@ -232,6 +233,9 @@ class PangeaRequest(PangeaRequestBase):
232
233
  if data is None:
233
234
  data = {}
234
235
 
236
+ # Normalize.
237
+ data = cast(dict[str, Any], to_jsonable_python(data))
238
+
235
239
  if url is None:
236
240
  url = self._url(endpoint)
237
241
 
@@ -402,20 +406,7 @@ class PangeaRequest(PangeaRequestBase):
402
406
 
403
407
  return self._check_response(pangea_response)
404
408
 
405
- def download_file(self, url: str, filename: str | None = None) -> AttachedFile:
406
- """
407
- Download file
408
-
409
- Download a file from the specified URL and save it with the given
410
- filename.
411
-
412
- Args:
413
- url: URL of the file to download
414
- filename: Name to save the downloaded file as. If not provided, the
415
- filename will be determined from the Content-Disposition header or
416
- the URL.
417
- """
418
-
409
+ def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile:
419
410
  self.logger.debug(
420
411
  json.dumps(
421
412
  {
@@ -1,9 +1,11 @@
1
1
  from .audit.audit import Audit
2
2
  from .authn.authn import AuthN
3
3
  from .authz import AuthZ
4
+ from .data_guard import DataGuard
4
5
  from .embargo import Embargo
5
6
  from .file_scan import FileScan
6
7
  from .intel import DomainIntel, FileIntel, IpIntel, UrlIntel, UserIntel
8
+ from .prompt_guard import PromptGuard
7
9
  from .redact import Redact
8
10
  from .sanitize import Sanitize
9
11
  from .share.share import Share
@@ -492,7 +492,7 @@ class Audit(ServiceBase, AuditBase):
492
492
  verbose: Optional[bool] = None,
493
493
  ) -> PangeaResponse[LogResult]:
494
494
  """
495
- Log an event
495
+ Log an entry
496
496
 
497
497
  Create a log entry in the Secure Audit Log.
498
498
 
@@ -501,7 +501,6 @@ class Audit(ServiceBase, AuditBase):
501
501
  verify (bool, optional): True to verify logs consistency after response.
502
502
  sign_local (bool, optional): True to sign event with local key.
503
503
  verbose (bool, optional): True to get a more verbose response.
504
-
505
504
  Raises:
506
505
  AuditException: If an audit based api exception happens
507
506
  PangeaAPIException: If an API Error happens
@@ -512,7 +511,13 @@ class Audit(ServiceBase, AuditBase):
512
511
  Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v1/log).
513
512
 
514
513
  Examples:
515
- response = audit.log_event({"message": "hello world"}, verbose=True)
514
+ try:
515
+ log_response = audit.log({"message": "hello world"}, verbose=True)
516
+ print(f"Response. Hash: {log_response.result.hash}")
517
+ except pe.PangeaAPIException as e:
518
+ print(f"Request Error: {e.response.summary}")
519
+ for err in e.errors:
520
+ print(f"\\t{err.detail} \\n")
516
521
  """
517
522
 
518
523
  input = self._get_log_request(event, sign_local=sign_local, verify=verify, verbose=verbose)
@@ -956,9 +961,9 @@ class Audit(ServiceBase, AuditBase):
956
961
  if pub_root is not None:
957
962
  self.pub_roots[tree_size] = pub_root
958
963
 
959
- self._fix_consistency_proofs(tree_sizes)
964
+ self.fix_consistency_proofs(tree_sizes)
960
965
 
961
- def _fix_consistency_proofs(self, tree_sizes: Iterable[int]) -> None:
966
+ def fix_consistency_proofs(self, tree_sizes: Iterable[int]):
962
967
  # on very rare occasions, the consistency proof in Arweave may be wrong
963
968
  # override it with the proof from pangea (not the root hash, just the proof)
964
969
  for tree_size in tree_sizes:
pangea/services/authz.py CHANGED
@@ -1,11 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
3
 
5
4
  import enum
6
5
  from typing import Any, Dict, List, Optional, Union
7
6
 
8
- from pangea.config import PangeaConfig
9
7
  from pangea.response import APIRequestModel, APIResponseModel, PangeaResponse, PangeaResponseResult
10
8
  from pangea.services.base import ServiceBase
11
9
 
@@ -173,25 +171,7 @@ class AuthZ(ServiceBase):
173
171
 
174
172
  service_name = "authz"
175
173
 
176
- def __init__(
177
- self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
178
- ) -> None:
179
- """
180
- AuthZ client
181
-
182
- Initializes a new AuthZ client.
183
-
184
- Args:
185
- token: Pangea API token.
186
- config: Configuration.
187
- logger_name: Logger name.
188
- config_id: Configuration ID.
189
-
190
- Examples:
191
- config = PangeaConfig(domain="aws.us.pangea.cloud")
192
- authz = AuthZ(token="pangea_token", config=config)
193
- """
194
-
174
+ def __init__(self, token: str, config=None, logger_name="pangea", config_id: Optional[str] = None):
195
175
  super().__init__(token, config, logger_name, config_id=config_id)
196
176
 
197
177
  def tuple_create(self, tuples: List[Tuple]) -> PangeaResponse[TupleCreateResult]:
pangea/services/base.py CHANGED
@@ -80,8 +80,7 @@ class ServiceBase(object):
80
80
  Returns request's result that has been accepted by the server
81
81
 
82
82
  Args:
83
- exception: Exception that was previously raised by the SDK on a call
84
- that is being processed.
83
+ exception (AcceptedRequestException): Exception raise by SDK on the call that is been processed.
85
84
 
86
85
  Returns:
87
86
  PangeaResponse
@@ -101,18 +100,5 @@ class ServiceBase(object):
101
100
  else:
102
101
  raise AttributeError("Need to set exception, response or request_id")
103
102
 
104
- def download_file(self, url: str, filename: str | None = None) -> AttachedFile:
105
- """
106
- Download file
107
-
108
- Download a file from the specified URL and save it with the given
109
- filename.
110
-
111
- Args:
112
- url: URL of the file to download
113
- filename: Name to save the downloaded file as. If not provided, the
114
- filename will be determined from the Content-Disposition header or
115
- the URL.
116
- """
117
-
103
+ def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile:
118
104
  return self.request.download_file(url=url, filename=filename)
@@ -0,0 +1,147 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import List, Optional
4
+
5
+ from typing_extensions import Literal
6
+
7
+ from pangea.response import PangeaResponse, PangeaResponseResult
8
+ from pangea.services.base import ServiceBase
9
+ from pangea.services.intel import UserBreachedData
10
+
11
+
12
+ class TextGuardSecurityIssues(PangeaResponseResult):
13
+ compromised_email_addresses: int
14
+ malicious_domain_count: int
15
+ malicious_ip_count: int
16
+ malicious_url_count: int
17
+ redacted_item_count: int
18
+
19
+
20
+ class TextGuardFindings(PangeaResponseResult):
21
+ artifact_count: int
22
+ malicious_count: int
23
+ security_issues: TextGuardSecurityIssues
24
+
25
+
26
+ class RedactRecognizerResult(PangeaResponseResult):
27
+ field_type: str
28
+ """The entity name."""
29
+
30
+ score: float
31
+ """The certainty score that the entity matches this specific snippet."""
32
+
33
+ text: str
34
+ """The text snippet that matched."""
35
+
36
+ start: int
37
+ """The starting index of a snippet."""
38
+
39
+ end: int
40
+ """The ending index of a snippet."""
41
+
42
+ redacted: bool
43
+ """Indicates if this rule was used to anonymize a text snippet."""
44
+
45
+
46
+ class RedactReport(PangeaResponseResult):
47
+ count: int
48
+ recognizer_results: List[RedactRecognizerResult]
49
+
50
+
51
+ class IntelResults(PangeaResponseResult):
52
+ category: List[str]
53
+ """
54
+ The categories that apply to this indicator as determined by the provider.
55
+ """
56
+
57
+ score: int
58
+ """The score, given by the Pangea service, for the indicator."""
59
+
60
+ verdict: Literal["malicious", "suspicious", "unknown", "benign"]
61
+
62
+
63
+ class TextGuardReport(PangeaResponseResult):
64
+ domain_intel: Optional[IntelResults] = None
65
+ ip_intel: Optional[IntelResults] = None
66
+ redact: RedactReport
67
+ url_intel: Optional[IntelResults] = None
68
+ user_intel: Optional[UserBreachedData] = None
69
+
70
+
71
+ class TextGuardArtifact(PangeaResponseResult):
72
+ defanged: bool
73
+ end: int
74
+ start: int
75
+ type: str
76
+ value: str
77
+ verdict: Optional[str] = None
78
+ """The verdict, given by the Pangea service, for the indicator."""
79
+
80
+
81
+ class TextGuardResult(PangeaResponseResult):
82
+ artifacts: Optional[List[TextGuardArtifact]] = None
83
+ findings: TextGuardFindings
84
+ redacted_prompt: str
85
+
86
+ # `debug=True` only.
87
+ report: Optional[TextGuardReport] = None
88
+
89
+
90
+ class DataGuard(ServiceBase):
91
+ """Data Guard service client.
92
+
93
+ Provides methods to interact with Pangea's Data Guard service.
94
+ """
95
+
96
+ service_name = "data-guard"
97
+
98
+ def guard_text(
99
+ self,
100
+ text: str,
101
+ *,
102
+ recipe: str = "pangea_prompt_guard",
103
+ debug: bool = False,
104
+ ) -> PangeaResponse[TextGuardResult]:
105
+ """
106
+ Text guard (Beta)
107
+
108
+ Guard text.
109
+
110
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
111
+
112
+ OperationId: data_guard_post_v1_text_guard
113
+
114
+ Args:
115
+ text: Text.
116
+ recipe: Recipe.
117
+ debug: Debug.
118
+
119
+ Examples:
120
+ response = data_guard.guard_text("text")
121
+ """
122
+
123
+ return self.request.post(
124
+ "v1/text/guard", TextGuardResult, data={"text": text, "recipe": recipe, "debug": debug}
125
+ )
126
+
127
+ def guard_file(
128
+ self,
129
+ file_url: str,
130
+ ) -> PangeaResponse[PangeaResponseResult]:
131
+ """
132
+ File guard (Beta)
133
+
134
+ Guard a file URL.
135
+
136
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
137
+
138
+ OperationId: data_guard_post_v1_file_guard
139
+
140
+ Args:
141
+ file_url: File URL.
142
+
143
+ Examples:
144
+ response = data_guard.guard_file("https://example.org/file.txt")
145
+ """
146
+
147
+ return self.request.post("v1/file/guard", PangeaResponseResult, data={"file_url": file_url})
pangea/services/intel.py CHANGED
@@ -1,7 +1,5 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
-
5
3
  import enum
6
4
  import hashlib
7
5
  from typing import Dict, List, Optional
@@ -1239,7 +1237,6 @@ class UserBreachedRequest(IntelCommonRequest):
1239
1237
  phone_number (str): A phone number to search for. minLength: 7, maxLength: 15.
1240
1238
  start (str): Earliest date for search
1241
1239
  end (str): Latest date for search
1242
- cursor (str, optional): A token given in the raw response from SpyCloud. Post this back to paginate results
1243
1240
  """
1244
1241
 
1245
1242
  email: Optional[str] = None
@@ -1248,7 +1245,6 @@ class UserBreachedRequest(IntelCommonRequest):
1248
1245
  phone_number: Optional[str] = None
1249
1246
  start: Optional[str] = None
1250
1247
  end: Optional[str] = None
1251
- cursor: Optional[str] = None
1252
1248
 
1253
1249
 
1254
1250
  class UserBreachedBulkRequest(IntelCommonRequest):
@@ -1391,7 +1387,6 @@ class UserIntel(ServiceBase):
1391
1387
  verbose: Optional[bool] = None,
1392
1388
  raw: Optional[bool] = None,
1393
1389
  provider: Optional[str] = None,
1394
- cursor: Optional[str] = None,
1395
1390
  ) -> PangeaResponse[UserBreachedResult]:
1396
1391
  """
1397
1392
  Look up breached users
@@ -1410,7 +1405,6 @@ class UserIntel(ServiceBase):
1410
1405
  verbose (bool, optional): Echo the API parameters in the response
1411
1406
  raw (bool, optional): Include raw data from this provider
1412
1407
  provider (str, optional): Use reputation data from this provider: "spycloud"
1413
- cursor (str, optional): A token given in the raw response from SpyCloud. Post this back to paginate results
1414
1408
 
1415
1409
  Raises:
1416
1410
  PangeaAPIException: If an API Error happens
@@ -1438,7 +1432,6 @@ class UserIntel(ServiceBase):
1438
1432
  end=end,
1439
1433
  verbose=verbose,
1440
1434
  raw=raw,
1441
- cursor=cursor,
1442
1435
  )
1443
1436
  return self.request.post("v1/user/breached", UserBreachedResult, data=input.model_dump(exclude_none=True))
1444
1437
 
@@ -1599,17 +1592,6 @@ class UserIntel(ServiceBase):
1599
1592
 
1600
1593
  @staticmethod
1601
1594
  def is_password_breached(response: PangeaResponse[UserBreachedResult], hash: str) -> PasswordStatus:
1602
- """
1603
- Check if a password was breached
1604
-
1605
- Helper function that simplifies searching the response's raw data for
1606
- the full hash.
1607
-
1608
- Args:
1609
- response: API response from an earlier request
1610
- hash: Password hash
1611
- """
1612
-
1613
1595
  if response.result.raw_data is None: # type: ignore[union-attr]
1614
1596
  raise PangeaException("Need raw data to check if hash is breached. Send request with raw=true")
1615
1597
 
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult
6
+ from pangea.services.base import ServiceBase
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Iterable
10
+
11
+
12
+ class Message(APIRequestModel):
13
+ role: str
14
+ content: str
15
+
16
+
17
+ class GuardResult(PangeaResponseResult):
18
+ prompt_injection_detected: bool
19
+ prompt_injection_type: Optional[str] = None
20
+ prompt_injection_detector: Optional[str] = None
21
+
22
+
23
+ class PromptGuard(ServiceBase):
24
+ """Prompt Guard service client.
25
+
26
+ Provides methods to interact with Pangea's Prompt Guard service.
27
+ """
28
+
29
+ service_name = "prompt-guard"
30
+
31
+ def guard(self, messages: Iterable[Message]) -> PangeaResponse[GuardResult]:
32
+ """
33
+ Guard (Beta)
34
+
35
+ Guard messages.
36
+
37
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
38
+
39
+ OperationId: prompt_guard_post_v1_guard
40
+
41
+ Args:
42
+ messages: Messages.
43
+
44
+ Examples:
45
+ response = prompt_guard.guard([Message(role="user", content="hello world")])
46
+ """
47
+
48
+ return self.request.post("v1/guard", GuardResult, data={"messages": messages})
pangea/services/redact.py CHANGED
@@ -66,18 +66,6 @@ class RedactRequest(APIRequestModel):
66
66
  rulesets: Optional[List[str]] = None
67
67
  return_result: Optional[bool] = None
68
68
  redaction_method_overrides: Optional[RedactionMethodOverrides] = None
69
- vault_parameters: Optional[VaultParameters] = None
70
-
71
- llm_request: Optional[bool] = None
72
- """Is this redact call going to be used in an LLM request?"""
73
-
74
-
75
- class VaultParameters(APIRequestModel):
76
- fpe_key_id: Optional[str] = None
77
- """A vault key ID of an exportable key used to redact with FPE instead of using the service config default."""
78
-
79
- salt_secret_id: Optional[str] = None
80
- """A vault secret ID of a secret used to salt a hash instead of using the service config default."""
81
69
 
82
70
 
83
71
  class RecognizerResult(APIResponseModel):
@@ -146,10 +134,6 @@ class StructuredRequest(APIRequestModel):
146
134
  rulesets: Optional[List[str]] = None
147
135
  return_result: Optional[bool] = None
148
136
  redaction_method_overrides: Optional[RedactionMethodOverrides] = None
149
- vault_parameters: Optional[VaultParameters] = None
150
-
151
- llm_request: Optional[bool] = None
152
- """Is this redact call going to be used in an LLM request?"""
153
137
 
154
138
 
155
139
  class StructuredResult(PangeaResponseResult):
@@ -7,7 +7,6 @@ from typing import Dict, List, Optional, Tuple
7
7
 
8
8
  from pydantic import Field
9
9
 
10
- from pangea.config import PangeaConfig
11
10
  from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult, TransferMethod
12
11
  from pangea.services.base import ServiceBase
13
12
  from pangea.utils import FileUploadParams, get_file_upload_params
@@ -198,27 +197,6 @@ class Sanitize(ServiceBase):
198
197
 
199
198
  service_name = "sanitize"
200
199
 
201
- def __init__(
202
- self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
203
- ) -> None:
204
- """
205
- Sanitize client
206
-
207
- Initializes a new Sanitize client.
208
-
209
- Args:
210
- token: Pangea API token.
211
- config: Configuration.
212
- logger_name: Logger name.
213
- config_id: Configuration ID.
214
-
215
- Examples:
216
- config = PangeaConfig(domain="aws.us.pangea.cloud")
217
- authz = Sanitize(token="pangea_token", config=config)
218
- """
219
-
220
- super().__init__(token, config, logger_name, config_id=config_id)
221
-
222
200
  def sanitize(
223
201
  self,
224
202
  transfer_method: TransferMethod = TransferMethod.POST_URL,
@@ -6,7 +6,6 @@ import enum
6
6
  import io
7
7
  from typing import Dict, List, NewType, Optional, Tuple, Union
8
8
 
9
- from pangea.config import PangeaConfig
10
9
  from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult, TransferMethod
11
10
  from pangea.services.base import ServiceBase
12
11
  from pangea.services.share.file_format import FileFormat
@@ -670,31 +669,10 @@ class BucketsResult(PangeaResponseResult):
670
669
 
671
670
 
672
671
  class Share(ServiceBase):
673
- """Secure Share service client."""
672
+ """Share service client."""
674
673
 
675
674
  service_name = "share"
676
675
 
677
- def __init__(
678
- self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
679
- ) -> None:
680
- """
681
- Secure Share client
682
-
683
- Initializes a new Secure Share client.
684
-
685
- Args:
686
- token: Pangea API token.
687
- config: Configuration.
688
- logger_name: Logger name.
689
- config_id: Configuration ID.
690
-
691
- Examples:
692
- config = PangeaConfig(domain="aws.us.pangea.cloud")
693
- authz = Share(token="pangea_token", config=config)
694
- """
695
-
696
- super().__init__(token, config, logger_name, config_id=config_id)
697
-
698
676
  def buckets(self) -> PangeaResponse[BucketsResult]:
699
677
  """
700
678
  Buckets
pangea/utils.py CHANGED
@@ -6,6 +6,7 @@ import datetime
6
6
  import io
7
7
  import json
8
8
  from hashlib import md5, new, sha1, sha256, sha512
9
+ from typing import Union
9
10
 
10
11
  from google_crc32c import Checksum as CRC32C
11
12
  from pydantic import BaseModel
@@ -66,7 +67,7 @@ def canonicalize(data: dict) -> str:
66
67
  return str(data)
67
68
 
68
69
 
69
- def hash_sha256(input: str | io.BufferedReader) -> str:
70
+ def hash_sha256(input: Union[str, io.BufferedReader]) -> str:
70
71
  # Return SHA256 hash in hex format
71
72
  hash = sha256()
72
73
  if isinstance(input, io.BufferedReader):
@@ -79,12 +80,12 @@ def hash_sha256(input: str | io.BufferedReader) -> str:
79
80
 
80
81
  input.seek(0) # restart reading
81
82
  else:
82
- hash.update(input.encode("utf-8"))
83
+ hash.update(input) # type: ignore
83
84
 
84
85
  return hash.hexdigest()
85
86
 
86
87
 
87
- def hash_sha1(input: str | io.BufferedReader) -> str:
88
+ def hash_sha1(input: Union[str, io.BufferedReader]) -> str:
88
89
  # Return SHA1 hash in hex format
89
90
  hash = sha1()
90
91
  if isinstance(input, io.BufferedReader):
@@ -97,12 +98,12 @@ def hash_sha1(input: str | io.BufferedReader) -> str:
97
98
 
98
99
  input.seek(0) # restart reading
99
100
  else:
100
- hash.update(input.encode("utf-8"))
101
+ hash.update(input) # type: ignore
101
102
 
102
103
  return hash.hexdigest()
103
104
 
104
105
 
105
- def hash_sha512(input: str | io.BufferedReader) -> str:
106
+ def hash_sha512(input: Union[str, io.BufferedReader]) -> str:
106
107
  # Return SHA512 hash in hex format
107
108
  hash = sha512()
108
109
  if isinstance(input, io.BufferedReader):
@@ -115,7 +116,7 @@ def hash_sha512(input: str | io.BufferedReader) -> str:
115
116
 
116
117
  input.seek(0) # restart reading
117
118
  else:
118
- hash.update(input.encode("utf-8"))
119
+ hash.update(input) # type: ignore
119
120
 
120
121
  return hash.hexdigest()
121
122
 
@@ -125,7 +126,7 @@ def hash_ntlm(data: str) -> str:
125
126
  return new("md4", data.encode("utf-16le")).hexdigest()
126
127
 
127
128
 
128
- def hash_md5(input: str | io.BufferedReader) -> str:
129
+ def hash_md5(input: Union[str, io.BufferedReader]) -> str:
129
130
  # Return MD5 hash in hex format
130
131
  hash = md5()
131
132
  if isinstance(input, io.BufferedReader):
@@ -139,7 +140,7 @@ def hash_md5(input: str | io.BufferedReader) -> str:
139
140
 
140
141
  input.seek(0) # restart reading
141
142
  else:
142
- hash.update(input.encode("utf-8"))
143
+ hash.update(input) # type: ignore
143
144
 
144
145
  return hash.hexdigest()
145
146
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pangea-sdk
3
- Version: 5.2.0
3
+ Version: 5.2.0b1
4
4
  Summary: Pangea API SDK
5
5
  Home-page: https://pangea.cloud/docs/sdk/python/
6
6
  License: MIT
@@ -17,11 +17,11 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Topic :: Software Development
19
19
  Classifier: Topic :: Software Development :: Libraries
20
- Requires-Dist: aiohttp (>=3.11.10,<4.0.0)
21
- Requires-Dist: cryptography (>=43.0.3,<44.0.0)
22
- Requires-Dist: deprecated (>=1.2.15,<2.0.0)
20
+ Requires-Dist: aiohttp (>=3.10.10,<4.0.0)
21
+ Requires-Dist: cryptography (>=43.0.1,<44.0.0)
22
+ Requires-Dist: deprecated (>=1.2.14,<2.0.0)
23
23
  Requires-Dist: google-crc32c (>=1.5.0,<2.0.0)
24
- Requires-Dist: pydantic (>=2.10.3,<3.0.0)
24
+ Requires-Dist: pydantic (>=2.9.2,<3.0.0)
25
25
  Requires-Dist: python-dateutil (>=2.9.0,<3.0.0)
26
26
  Requires-Dist: requests (>=2.31.0,<3.0.0)
27
27
  Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
@@ -64,10 +64,9 @@ $ poetry add pangea-sdk
64
64
  #### Beta releases
65
65
 
66
66
  Pre-release versions may be available with the `b` (beta) denotation in the
67
- version number. These releases serve to preview Beta and Early Access services
68
- and APIs. Per Semantic Versioning, they are considered unstable and do not carry
69
- the same compatibility guarantees as stable releases.
70
- [Beta changelog](https://github.com/pangeacyber/pangea-python/blob/beta/CHANGELOG.md).
67
+ version number. These releases serve to preview beta services and APIs. Per
68
+ Semantic Versioning, they are considered unstable and do not carry the same
69
+ compatibility guarantees as stable releases. [Beta changelog](https://github.com/pangeacyber/pangea-python/blob/beta/CHANGELOG.md).
71
70
 
72
71
  Via pip:
73
72
 
@@ -1,47 +1,51 @@
1
- pangea/__init__.py,sha256=9eKOhXARZe6eGTwrLyOBGfDQV02cZF1aQ4GVGjL1yyc,246
1
+ pangea/__init__.py,sha256=DOhpkGYAdPZn1XFB2SFVZRtUkHB0rrqx21nRI5UVs08,251
2
2
  pangea/asyncio/__init__.py,sha256=kjEMkqMQ521LlMSu5jn3_WgweyArwVZ2C-s3x7mR6Pk,45
3
3
  pangea/asyncio/file_uploader.py,sha256=wI7epib7Rc5jtZw4eJ1L1SlmutDG6CPv59C8N2UPhtY,1436
4
- pangea/asyncio/request.py,sha256=BREsLY8_MCxGSplHbdKFZTzr4TX5ya0-BsXLffZhsco,17849
4
+ pangea/asyncio/request.py,sha256=Pwk3dAzO_A7I1NyrIqK5V80xvtAL80KiNSjbrXjzQzA,17519
5
5
  pangea/asyncio/services/__init__.py,sha256=3IkiTqY_RtFndI7aoDTrb1yLv8xos_cKhmGS1TULcmw,386
6
- pangea/asyncio/services/audit.py,sha256=rPaCx4cMzj-g9WFMRIysFCJAz6Btp6YrhcKe_exky8k,26283
6
+ pangea/asyncio/services/audit.py,sha256=bZ7gdkVWkzqLqUVc1Wnf3oDAaCLg97-zTWhY8UdX0_Y,26549
7
7
  pangea/asyncio/services/authn.py,sha256=rPeLJweL8mYH_t4ebcQn4n_Wglr3kClKNnCXNCimZU4,46622
8
- pangea/asyncio/services/authz.py,sha256=B_0_nhDMJcjNpjpCx3Vi2LDRhlmfV9325GKbUZ8reos,10025
9
- pangea/asyncio/services/base.py,sha256=vRFVcO_uEAGJte3OUUBLD43RoiiFB1vC7SPyN6yEMoA,3158
8
+ pangea/asyncio/services/authz.py,sha256=HgW9R8DeW19wS7fpgq0NWOx41wZWcn6NYS4NMbi8p1A,9482
9
+ pangea/asyncio/services/base.py,sha256=4FtKtlq74NmE9myrgIt9HMA6JDnP4mPZ6krafWr286o,2663
10
+ pangea/asyncio/services/data_guard.py,sha256=f6VzZCcfAHpttCjqt5SExtbsrH1HkIRFmZ2c3nRlcwU,1713
10
11
  pangea/asyncio/services/embargo.py,sha256=ctzj3kip6xos-Eu3JuOskrCGYC8T3JlsgAopZHiPSXM,3068
11
12
  pangea/asyncio/services/file_scan.py,sha256=PLG1O-PL4Yk9uY9D6NbMrZ5LHg70Z311s7bFe46UMZA,7108
12
- pangea/asyncio/services/intel.py,sha256=Iwz_DleAPtmd1taekT4W8lVo65uHjIvA4TQ7WUQGrRk,38306
13
+ pangea/asyncio/services/intel.py,sha256=cCm3VwWxUzEUCNhuPCeejJvr4uOeLXuYDbDwTzNG6Aw,38121
14
+ pangea/asyncio/services/prompt_guard.py,sha256=oKnJM-ykWmFdbcdYzDPmjgY4P09a3fyzYuCDc2p0G5M,1044
13
15
  pangea/asyncio/services/redact.py,sha256=jRNtXr_DZ_cY7guhut-eZmOEhy2uN_VCXrjGH6bkh74,7265
14
- pangea/asyncio/services/sanitize.py,sha256=4pRWBH595kFUXBkmu8euyk6H7F1M_-xXB2Qxnz6St6c,8627
15
- pangea/asyncio/services/share.py,sha256=YPJm_Gc4tfcx2cX6P_vLWIsHOR6M3RYy9LdU2UzEZbk,26791
16
+ pangea/asyncio/services/sanitize.py,sha256=bf98J-s-P51oSKqNBgR0wj5mlHOCBwpjWz7k0NdXCKQ,7899
17
+ pangea/asyncio/services/share.py,sha256=UYJeUKA3NLSFA8R0X7B6yBi2U1g4q04O4ftrp9SMCzA,26097
16
18
  pangea/asyncio/services/vault.py,sha256=VqrJGSEdq6MlZRI6cJpkthhIsqLClSQdgVxwYCbIwEk,77079
17
19
  pangea/audit_logger.py,sha256=gRkCfUUT5LDNaycwxkhZUySgY47jDfn1ZeKOul4XCQI,3842
18
20
  pangea/config.py,sha256=mQUu8GX_6weIuv3vjNdG5plppXskXYASmxMWtFQh-hc,1662
19
21
  pangea/crypto/rsa.py,sha256=mwSiNy571KAGr3F6oEM0CXWkl9D023ch8ldbZZeLj_4,4747
20
- pangea/deep_verify.py,sha256=ZGraaL7TCxwRBIDqjBFR0clKlhAC-Yce6kD-1LClhG8,8616
22
+ pangea/deep_verify.py,sha256=mocaGbC6XLbMTVWxTpMv4oJtXGPWpT-SbFqT3obpiZs,8443
21
23
  pangea/deprecated.py,sha256=IjFYEVvY1E0ld0SMkEYC1o62MAleX3nnT1If2dFVbHo,608
22
- pangea/dump_audit.py,sha256=IevqaUUh7GDepdIW7slSxeZbkPrWIVbcX3sr4DgpJXI,7090
24
+ pangea/dump_audit.py,sha256=1Je8D2fXwU4PWcZ-ZD4icfO3DNFvWqJkwsac4qFEhOo,7025
23
25
  pangea/exceptions.py,sha256=OBtzUECpNa6vNp8ySkHC-tm4QjFRCOAHBkMHqzAlOu8,5656
24
26
  pangea/file_uploader.py,sha256=4RQ44xt-faApC61nn2PlwHT7XYrJ4GeQA8Ug4tySEAg,1227
25
27
  pangea/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- pangea/request.py,sha256=zxFvqbeGYtxN29nS8SPPZKlcGCqdUtenxaq84pQ4cxs,24807
28
+ pangea/request.py,sha256=ZRH4NCnbzjpzkcNnOomelK5uB49T_20PfHP_j4Swgmw,24545
27
29
  pangea/response.py,sha256=lPAcYsF9Xg166CiyhCofVmQA-W4jevh0MQXxUa8Re68,7737
28
- pangea/services/__init__.py,sha256=-QsZxRzRq_V1x1lmS_mu4310MNm0DkM4r6g6rfVGnOc,340
29
- pangea/services/audit/audit.py,sha256=7-c9l7jyGtpG7SqRUMpqsAzcUDhMZ5izgPalxHXsUvM,39320
30
+ pangea/services/__init__.py,sha256=LmW8wdR3Vyi2_-rI9xqc9eHeQIjbfaO4e_Z3FMjNEFc,412
31
+ pangea/services/audit/audit.py,sha256=IFv7jANA8S2SypQVS47x94_Cr5Z9zSsL9Dp9eXw9RHk,39593
30
32
  pangea/services/audit/exceptions.py,sha256=bhVuYe4ammacOVxwg98CChxvwZf5FKgR2DcgqILOcwc,471
31
33
  pangea/services/audit/models.py,sha256=1h1B9eSYQMYG3f8WNi1UcDX2-impRrET_ErjJYUnj7M,14678
32
34
  pangea/services/audit/signing.py,sha256=5A4hvPtpfP2kMz8bsiiKUACriXbh5dv9gb_rbqiUtuI,5583
33
35
  pangea/services/audit/util.py,sha256=Zq1qvfeplYfhCP_ud5YMvntSB0UvnCdsuYbOzZkHbjg,7620
34
36
  pangea/services/authn/authn.py,sha256=cZKl2Ixc6HwHnkRecpSaAGTQUgaZUtxfLa0T3S03HMs,45478
35
37
  pangea/services/authn/models.py,sha256=HH5su6jx3O9AwVGzASXZ99-eIWjgXEP5LhIVdewM13s,22394
36
- pangea/services/authz.py,sha256=bB0ZEUuXLT7Xjs5kZef1hZK6Du6VUusHe5aekNaxamw,12746
37
- pangea/services/base.py,sha256=43pWQcR9CeT4sGzgctF3Sy4M_h7DaUzkuZD2Z7CcDUU,3845
38
+ pangea/services/authz.py,sha256=HfDnovAokzAHvnjYdOCwceM-1sCmzODnjNEbQBUSfo8,12222
39
+ pangea/services/base.py,sha256=lwhHoe5Juy28Ir3Mfj2lHdM58gxZRaxa2SRFi4_DBRw,3453
40
+ pangea/services/data_guard.py,sha256=CzJ4Q-aakmWm8NhaWNWkT0QA6zFlyY49j2yerGOPUmc,3689
38
41
  pangea/services/embargo.py,sha256=9Wfku4td5ORaIENKmnGmS5jxJJIRfWp6Q51L36Jsy0I,3897
39
42
  pangea/services/file_scan.py,sha256=QiO80uKqB_BnAOiYQKznXfxpa5j40qqETE3-zBRT_QE,7813
40
- pangea/services/intel.py,sha256=flVdK4WhllPutCkWh7H-MuBxMMz0f4Bl-fz2f-hPuWM,52679
41
- pangea/services/redact.py,sha256=nst-mfxI7ewkDSSVVoY9cznMgb7EY9TGCjD6ZpPGvY4,12128
42
- pangea/services/sanitize.py,sha256=D_R_XIe9FvRCX40b8b_3gouhAGduDdxI9bT2w-kiVHU,13444
43
+ pangea/services/intel.py,sha256=CziBhC5K6O_kBXpD8zgJLpDtLHzBRgATGW4gHHFJT48,52039
44
+ pangea/services/prompt_guard.py,sha256=i0wlUjOMhdAuJytXp72OXcSzQwaWcXUiJxon7xVOJqg,1233
45
+ pangea/services/redact.py,sha256=ZYXkzEoriLJyCqaj5dqmgsC56mIz4T3pPToZ7TcNfhg,11465
46
+ pangea/services/sanitize.py,sha256=XP5D4CcbCZfzgU567X6H5eFBWwZuYSsHdvsdrQAZekY,12767
43
47
  pangea/services/share/file_format.py,sha256=1svO1ee_aenA9zoO_AaU-Rk5Ulp7kcPOc_KwNoluyQE,2797
44
- pangea/services/share/share.py,sha256=8N4zXQJjkVDf2iR62pz6xpmxlbXRPNfHgYfOuEdNaZ8,46333
48
+ pangea/services/share/share.py,sha256=iyP32UNWoT2F9C_65FiXWrVoNoO7dBjf0tVX1mF2Fz0,45644
45
49
  pangea/services/vault/models/asymmetric.py,sha256=vspijmEvHm5WXri_fjOWfQc4maYyZfhDkLuaTM8-PZo,4991
46
50
  pangea/services/vault/models/common.py,sha256=PSZRFqHTUtEMJJGwywEFM2AU3aV8S-sbcoo3LLQ6uTc,17981
47
51
  pangea/services/vault/models/keys.py,sha256=duAuTiOby_D7MloRvN4gNj0P-b-jx9sdtplAWFxsShw,2786
@@ -49,8 +53,8 @@ pangea/services/vault/models/secret.py,sha256=ItGdkulM-SEySfcm4a5yGxMvo_omjC7kCh
49
53
  pangea/services/vault/models/symmetric.py,sha256=t8xCM1wGGKDBpOqTggFueO4-4-2IFmyxqcs7_PDr7U0,2562
50
54
  pangea/services/vault/vault.py,sha256=ow-Zm7PYzfWIfUcA4UNnpeL2DHfZM4C7inRDmNR3zQU,76196
51
55
  pangea/tools.py,sha256=2-Y4SAHWFv6Ocj42J_bWrVy27M5G3wi7a8LJn0dabHc,6427
52
- pangea/utils.py,sha256=dZ6MwFVEWXUgXvvDg-k6JnvVfsgslvtaBd7ez7afrqk,4983
56
+ pangea/utils.py,sha256=KNkWK8o9j4iRDLUfAiobL-Hy5fcAxjl0DOFWXAqLK3E,5032
53
57
  pangea/verify_audit.py,sha256=nSP17OzoSPdvezRExwfcf45H8ZPZnxZu-CbEp3qFJO0,17354
54
- pangea_sdk-5.2.0.dist-info/METADATA,sha256=0_T3gGYHKgvjYYIsf9UgTtm5B5tWAqLx8DtPqm4ny0E,7513
55
- pangea_sdk-5.2.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
56
- pangea_sdk-5.2.0.dist-info/RECORD,,
58
+ pangea_sdk-5.2.0b1.dist-info/METADATA,sha256=WZN1H9C4M0BcIs3Tk9Mm950jBEv3pX_2YKH8l9F4Quk,7497
59
+ pangea_sdk-5.2.0b1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
60
+ pangea_sdk-5.2.0b1.dist-info/RECORD,,