pangea-sdk 5.2.0__py3-none-any.whl → 5.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.
pangea/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "5.2.0"
1
+ __version__ = "5.2.0beta2"
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
  {
@@ -1,9 +1,11 @@
1
+ from .ai_guard import AIGuardAsync
1
2
  from .audit import AuditAsync
2
3
  from .authn import AuthNAsync
3
4
  from .authz import AuthZAsync
4
5
  from .embargo import EmbargoAsync
5
6
  from .file_scan import FileScanAsync
6
7
  from .intel import DomainIntelAsync, FileIntelAsync, IpIntelAsync, UrlIntelAsync, UserIntelAsync
8
+ from .prompt_guard import PromptGuardAsync
7
9
  from .redact import RedactAsync
8
10
  from .sanitize import SanitizeAsync
9
11
  from .share import ShareAsync
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ from pangea.asyncio.services.base import ServiceBaseAsync
4
+ from pangea.config import PangeaConfig
5
+ from pangea.response import PangeaResponse
6
+ from pangea.services.ai_guard import TextGuardResult
7
+
8
+
9
+ class AIGuardAsync(ServiceBaseAsync):
10
+ """AI Guard service client.
11
+
12
+ Provides methods to interact with Pangea's AI Guard service.
13
+
14
+ Examples:
15
+ from pangea import PangeaConfig
16
+ from pangea.asyncio.services import AIGuardAsync
17
+
18
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
19
+ ai_guard = AIGuardAsync(token="pangea_token", config=config)
20
+ """
21
+
22
+ service_name = "ai-guard"
23
+
24
+ def __init__(
25
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
26
+ ) -> None:
27
+ """
28
+ AI Guard service client.
29
+
30
+ Initializes a new AI Guard client.
31
+
32
+ Args:
33
+ token: Pangea API token.
34
+ config: Pangea service configuration.
35
+ logger_name: Logger name.
36
+ config_id: Configuration ID.
37
+
38
+ Examples:
39
+ from pangea import PangeaConfig
40
+ from pangea.asyncio.services import AIGuardAsync
41
+
42
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
43
+ ai_guard = AIGuardAsync(token="pangea_token", config=config)
44
+ """
45
+
46
+ super().__init__(token, config, logger_name, config_id)
47
+
48
+ async def guard_text(
49
+ self,
50
+ text: str,
51
+ *,
52
+ recipe: str = "pangea_prompt_guard",
53
+ debug: bool = False,
54
+ ) -> PangeaResponse[TextGuardResult]:
55
+ """
56
+ Text guard (Beta)
57
+
58
+ Guard text.
59
+
60
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
61
+
62
+ OperationId: ai_guard_post_v1beta_text_guard
63
+
64
+ Args:
65
+ text: Text.
66
+ recipe: Recipe.
67
+ debug: Debug.
68
+
69
+ Examples:
70
+ response = await ai_guard.guard_text("text")
71
+ """
72
+
73
+ return await self.request.post(
74
+ "v1beta/text/guard", TextGuardResult, data={"text": text, "recipe": recipe, "debug": debug}
75
+ )
@@ -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]:
@@ -63,21 +63,7 @@ class ServiceBaseAsync(ServiceBase):
63
63
  else:
64
64
  raise AttributeError("Need to set exception, response or request_id")
65
65
 
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
-
66
+ async def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile: # type: ignore[override]
81
67
  return await self.request.download_file(url=url, filename=filename)
82
68
 
83
69
  async def close(self):
@@ -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,73 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from pangea.asyncio.services.base import ServiceBaseAsync
6
+ from pangea.config import PangeaConfig
7
+ from pangea.services.prompt_guard import GuardResult, Message
8
+
9
+ if TYPE_CHECKING:
10
+ from collections.abc import Iterable
11
+
12
+ from pangea.response import PangeaResponse
13
+
14
+
15
+ class PromptGuardAsync(ServiceBaseAsync):
16
+ """Prompt Guard service client.
17
+
18
+ Provides methods to interact with Pangea's Prompt Guard service.
19
+
20
+ Examples:
21
+ from pangea import PangeaConfig
22
+ from pangea.asyncio.services import PromptGuardAsync
23
+
24
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
25
+ prompt_guard = PromptGuardAsync(token="pangea_token", config=config)
26
+ """
27
+
28
+ service_name = "prompt-guard"
29
+
30
+ def __init__(
31
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
32
+ ) -> None:
33
+ """
34
+ Prompt Guard service client.
35
+
36
+ Initializes a new Prompt Guard client.
37
+
38
+ Args:
39
+ token: Pangea API token.
40
+ config: Pangea service configuration.
41
+ logger_name: Logger name.
42
+ config_id: Configuration ID.
43
+
44
+ Examples:
45
+ from pangea import PangeaConfig
46
+ from pangea.asyncio.services import PromptGuardAsync
47
+
48
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
49
+ prompt_guard = PromptGuardAsync(token="pangea_token", config=config)
50
+ """
51
+
52
+ super().__init__(token, config, logger_name, config_id)
53
+
54
+ async def guard(self, messages: Iterable[Message]) -> PangeaResponse[GuardResult]:
55
+ """
56
+ Guard (Beta)
57
+
58
+ Guard messages.
59
+
60
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
61
+
62
+ OperationId: prompt_guard_post_v1beta_guard
63
+
64
+ Args:
65
+ messages: Messages.
66
+
67
+ Examples:
68
+ from pangea.asyncio.services.prompt_guard import Message
69
+
70
+ response = await prompt_guard.guard([Message(role="user", content="hello world")])
71
+ """
72
+
73
+ return await self.request.post("v1beta/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
+ from .ai_guard import AIGuard
1
2
  from .audit.audit import Audit
2
3
  from .authn.authn import AuthN
3
4
  from .authz import AuthZ
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
@@ -0,0 +1,157 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import List, Optional
4
+
5
+ from typing_extensions import Literal
6
+
7
+ from pangea.config import PangeaConfig
8
+ from pangea.response import PangeaResponse, PangeaResponseResult
9
+ from pangea.services.base import ServiceBase
10
+ from pangea.services.intel import UserBreachedData
11
+
12
+
13
+ class TextGuardSecurityIssues(PangeaResponseResult):
14
+ compromised_email_addresses: int
15
+ malicious_domain_count: int
16
+ malicious_ip_count: int
17
+ malicious_url_count: int
18
+ redact_rule_match_count: int
19
+
20
+
21
+ class TextGuardFindings(PangeaResponseResult):
22
+ artifact_count: Optional[int] = None
23
+ malicious_count: Optional[int] = None
24
+ security_issues: TextGuardSecurityIssues
25
+
26
+
27
+ class RedactRecognizerResult(PangeaResponseResult):
28
+ field_type: str
29
+ """The entity name."""
30
+
31
+ score: float
32
+ """The certainty score that the entity matches this specific snippet."""
33
+
34
+ text: str
35
+ """The text snippet that matched."""
36
+
37
+ start: int
38
+ """The starting index of a snippet."""
39
+
40
+ end: int
41
+ """The ending index of a snippet."""
42
+
43
+ redacted: bool
44
+ """Indicates if this rule was used to anonymize a text snippet."""
45
+
46
+
47
+ class RedactReport(PangeaResponseResult):
48
+ count: int
49
+ recognizer_results: List[RedactRecognizerResult]
50
+
51
+
52
+ class IntelResults(PangeaResponseResult):
53
+ category: List[str]
54
+ """
55
+ The categories that apply to this indicator as determined by the provider.
56
+ """
57
+
58
+ score: int
59
+ """The score, given by the Pangea service, for the indicator."""
60
+
61
+ verdict: Literal["malicious", "suspicious", "unknown", "benign"]
62
+
63
+
64
+ class TextGuardReport(PangeaResponseResult):
65
+ domain_intel: Optional[IntelResults] = None
66
+ ip_intel: Optional[IntelResults] = None
67
+ redact: RedactReport
68
+ url_intel: Optional[IntelResults] = None
69
+ user_intel: Optional[UserBreachedData] = None
70
+
71
+
72
+ class TextGuardArtifact(PangeaResponseResult):
73
+ defanged: bool
74
+ end: int
75
+ start: int
76
+ type: str
77
+ value: str
78
+ verdict: Optional[str] = None
79
+ """The verdict, given by the Pangea service, for the indicator."""
80
+
81
+
82
+ class TextGuardResult(PangeaResponseResult):
83
+ artifacts: Optional[List[TextGuardArtifact]] = None
84
+ findings: TextGuardFindings
85
+ redacted_prompt: str
86
+
87
+ # `debug=True` only.
88
+ report: Optional[TextGuardReport] = None
89
+
90
+
91
+ class AIGuard(ServiceBase):
92
+ """AI Guard service client.
93
+
94
+ Provides methods to interact with Pangea's AI Guard service.
95
+
96
+ Examples:
97
+ from pangea import PangeaConfig
98
+ from pangea.services import AIGuard
99
+
100
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
101
+ ai_guard = AIGuard(token="pangea_token", config=config)
102
+ """
103
+
104
+ service_name = "ai-guard"
105
+
106
+ def __init__(
107
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
108
+ ) -> None:
109
+ """
110
+ AI Guard service client.
111
+
112
+ Initializes a new AI Guard client.
113
+
114
+ Args:
115
+ token: Pangea API token.
116
+ config: Pangea service configuration.
117
+ logger_name: Logger name.
118
+ config_id: Configuration ID.
119
+
120
+ Examples:
121
+ from pangea import PangeaConfig
122
+ from pangea.services import AIGuard
123
+
124
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
125
+ ai_guard = AIGuard(token="pangea_token", config=config)
126
+ """
127
+
128
+ super().__init__(token, config, logger_name, config_id)
129
+
130
+ def guard_text(
131
+ self,
132
+ text: str,
133
+ *,
134
+ recipe: str = "pangea_prompt_guard",
135
+ debug: bool = False,
136
+ ) -> PangeaResponse[TextGuardResult]:
137
+ """
138
+ Text guard (Beta)
139
+
140
+ Guard text.
141
+
142
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
143
+
144
+ OperationId: ai_guard_post_v1beta_text_guard
145
+
146
+ Args:
147
+ text: Text.
148
+ recipe: Recipe.
149
+ debug: Debug.
150
+
151
+ Examples:
152
+ response = ai_guard.guard_text("text")
153
+ """
154
+
155
+ return self.request.post(
156
+ "v1beta/text/guard", TextGuardResult, data={"text": text, "recipe": recipe, "debug": debug}
157
+ )
@@ -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
@@ -101,18 +101,5 @@ class ServiceBase(object):
101
101
  else:
102
102
  raise AttributeError("Need to set exception, response or request_id")
103
103
 
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
-
104
+ def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile:
118
105
  return self.request.download_file(url=url, filename=filename)
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,83 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from pangea.config import PangeaConfig
6
+ from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult
7
+ from pangea.services.base import ServiceBase
8
+
9
+ if TYPE_CHECKING:
10
+ from collections.abc import Iterable
11
+
12
+
13
+ class Message(APIRequestModel):
14
+ role: str
15
+ content: str
16
+
17
+
18
+ class GuardResult(PangeaResponseResult):
19
+ detected: bool
20
+ type: Optional[str] = None
21
+ detector: Optional[str] = None
22
+ confidence: int
23
+
24
+
25
+ class PromptGuard(ServiceBase):
26
+ """Prompt Guard service client.
27
+
28
+ Provides methods to interact with Pangea's Prompt Guard service.
29
+
30
+ Examples:
31
+ from pangea import PangeaConfig
32
+ from pangea.services import PromptGuard
33
+
34
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
35
+ prompt_guard = PromptGuard(token="pangea_token", config=config)
36
+ """
37
+
38
+ service_name = "prompt-guard"
39
+
40
+ def __init__(
41
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
42
+ ) -> None:
43
+ """
44
+ Prompt Guard service client.
45
+
46
+ Initializes a new Prompt Guard client.
47
+
48
+ Args:
49
+ token: Pangea API token.
50
+ config: Pangea service configuration.
51
+ logger_name: Logger name.
52
+ config_id: Configuration ID.
53
+
54
+ Examples:
55
+ from pangea import PangeaConfig
56
+ from pangea.services import PromptGuard
57
+
58
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
59
+ prompt_guard = PromptGuard(token="pangea_token", config=config)
60
+ """
61
+
62
+ super().__init__(token, config, logger_name, config_id)
63
+
64
+ def guard(self, messages: Iterable[Message]) -> PangeaResponse[GuardResult]:
65
+ """
66
+ Guard (Beta)
67
+
68
+ Guard messages.
69
+
70
+ How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
71
+
72
+ OperationId: prompt_guard_post_v1beta_guard
73
+
74
+ Args:
75
+ messages: Messages.
76
+
77
+ Examples:
78
+ from pangea.services.prompt_guard import Message
79
+
80
+ response = prompt_guard.guard([Message(role="user", content="hello world")])
81
+ """
82
+
83
+ return self.request.post("v1beta/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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pangea-sdk
3
- Version: 5.2.0
3
+ Version: 5.2.0b2
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)
20
+ Requires-Dist: aiohttp (>=3.10.10,<4.0.0)
21
21
  Requires-Dist: cryptography (>=43.0.3,<44.0.0)
22
- Requires-Dist: deprecated (>=1.2.15,<2.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)
@@ -1,47 +1,51 @@
1
- pangea/__init__.py,sha256=9eKOhXARZe6eGTwrLyOBGfDQV02cZF1aQ4GVGjL1yyc,246
1
+ pangea/__init__.py,sha256=YW7Y-Lb2D13OAwVGQH3AL6xmqtVbLjqDaQFROwi_Yd4,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
5
- pangea/asyncio/services/__init__.py,sha256=3IkiTqY_RtFndI7aoDTrb1yLv8xos_cKhmGS1TULcmw,386
6
- pangea/asyncio/services/audit.py,sha256=rPaCx4cMzj-g9WFMRIysFCJAz6Btp6YrhcKe_exky8k,26283
4
+ pangea/asyncio/request.py,sha256=Pwk3dAzO_A7I1NyrIqK5V80xvtAL80KiNSjbrXjzQzA,17519
5
+ pangea/asyncio/services/__init__.py,sha256=L6Tdhjfx_ZECHskhLMPaCcOefi-r-imw6q_zlU4j-FY,464
6
+ pangea/asyncio/services/ai_guard.py,sha256=FxO8GRBztfOhpd7Kzj4-jWAiG0kb89-jVWL_AnbEou8,2142
7
+ pangea/asyncio/services/audit.py,sha256=bZ7gdkVWkzqLqUVc1Wnf3oDAaCLg97-zTWhY8UdX0_Y,26549
7
8
  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
9
+ pangea/asyncio/services/authz.py,sha256=HgW9R8DeW19wS7fpgq0NWOx41wZWcn6NYS4NMbi8p1A,9482
10
+ pangea/asyncio/services/base.py,sha256=1_W3ImEdH5C3rGynC_JWeKx1E2X9HHvUWBa5uRiZFNM,2763
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=gRh7Z-ZS21EN8vXXnK1OJ5kYvmOWxKppia8tZYeuhmM,2202
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=h36HzyIGaI5kO6l3UCwKHx_Kd-m_9mYVwn5MLRVzblI,408
31
+ pangea/services/ai_guard.py,sha256=W9OxmqQiC2ymDWAoE8FK3_8prDTQhHR8lz4xE81tlMM,4157
32
+ pangea/services/audit/audit.py,sha256=IFv7jANA8S2SypQVS47x94_Cr5Z9zSsL9Dp9eXw9RHk,39593
30
33
  pangea/services/audit/exceptions.py,sha256=bhVuYe4ammacOVxwg98CChxvwZf5FKgR2DcgqILOcwc,471
31
34
  pangea/services/audit/models.py,sha256=1h1B9eSYQMYG3f8WNi1UcDX2-impRrET_ErjJYUnj7M,14678
32
35
  pangea/services/audit/signing.py,sha256=5A4hvPtpfP2kMz8bsiiKUACriXbh5dv9gb_rbqiUtuI,5583
33
36
  pangea/services/audit/util.py,sha256=Zq1qvfeplYfhCP_ud5YMvntSB0UvnCdsuYbOzZkHbjg,7620
34
37
  pangea/services/authn/authn.py,sha256=cZKl2Ixc6HwHnkRecpSaAGTQUgaZUtxfLa0T3S03HMs,45478
35
38
  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
39
+ pangea/services/authz.py,sha256=HfDnovAokzAHvnjYdOCwceM-1sCmzODnjNEbQBUSfo8,12222
40
+ pangea/services/base.py,sha256=nnVVzw6Y_hej5Vcy0WvN_CR0BG_U5F5k_XTNiBX1we0,3464
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=baaYbYW_HoZJNB8NCIxxFjvJelqrl9UOtWa10-N1jgg,2312
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
@@ -51,6 +55,6 @@ pangea/services/vault/vault.py,sha256=ow-Zm7PYzfWIfUcA4UNnpeL2DHfZM4C7inRDmNR3zQ
51
55
  pangea/tools.py,sha256=2-Y4SAHWFv6Ocj42J_bWrVy27M5G3wi7a8LJn0dabHc,6427
52
56
  pangea/utils.py,sha256=dZ6MwFVEWXUgXvvDg-k6JnvVfsgslvtaBd7ez7afrqk,4983
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.0b2.dist-info/METADATA,sha256=j_pSOR8g6RfcYWO7D9lQhISqYHPzfUlc5VSFFYW1elo,7514
59
+ pangea_sdk-5.2.0b2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
60
+ pangea_sdk-5.2.0b2.dist-info/RECORD,,