pangea-sdk 5.5.0b4__py3-none-any.whl → 6.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pangea/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "5.5.0beta4"
1
+ __version__ = "6.0.0"
2
2
 
3
3
  from pangea.asyncio.request import PangeaRequestAsync
4
4
  from pangea.config import PangeaConfig
@@ -7,7 +7,7 @@ from typing_extensions import TypeVar
7
7
  from pangea.asyncio.services.base import ServiceBaseAsync
8
8
  from pangea.config import PangeaConfig
9
9
  from pangea.response import PangeaResponse
10
- from pangea.services.ai_guard import LogFields, TextGuardResult
10
+ from pangea.services.ai_guard import LogFields, Overrides, TextGuardResult
11
11
 
12
12
  _T = TypeVar("_T")
13
13
 
@@ -58,7 +58,7 @@ class AIGuardAsync(ServiceBaseAsync):
58
58
  *,
59
59
  recipe: str | None = None,
60
60
  debug: bool | None = None,
61
- llm_info: str | None = None,
61
+ overrides: Overrides | None = None,
62
62
  log_fields: LogFields | None = None,
63
63
  ) -> PangeaResponse[TextGuardResult[None]]:
64
64
  """
@@ -78,7 +78,6 @@ class AIGuardAsync(ServiceBaseAsync):
78
78
  are to be applied to the text, such as defang malicious URLs.
79
79
  debug: Setting this value to true will provide a detailed analysis
80
80
  of the text data
81
- llm_info: Short string hint for the LLM Provider information
82
81
  log_field: Additional fields to include in activity log
83
82
 
84
83
  Examples:
@@ -92,7 +91,7 @@ class AIGuardAsync(ServiceBaseAsync):
92
91
  messages: _T,
93
92
  recipe: str | None = None,
94
93
  debug: bool | None = None,
95
- llm_info: str | None = None,
94
+ overrides: Overrides | None = None,
96
95
  log_fields: LogFields | None = None,
97
96
  ) -> PangeaResponse[TextGuardResult[_T]]:
98
97
  """
@@ -113,59 +112,20 @@ class AIGuardAsync(ServiceBaseAsync):
113
112
  are to be applied to the text, such as defang malicious URLs.
114
113
  debug: Setting this value to true will provide a detailed analysis
115
114
  of the text data
116
- llm_info: Short string hint for the LLM Provider information
117
115
  log_field: Additional fields to include in activity log
118
116
 
119
117
  Examples:
120
118
  response = await ai_guard.guard_text(messages=[{"role": "user", "content": "hello world"}])
121
119
  """
122
120
 
123
- @overload
124
- async def guard_text(
125
- self,
126
- *,
127
- llm_input: _T,
128
- recipe: str | None = None,
129
- debug: bool | None = None,
130
- llm_info: str | None = None,
131
- log_fields: LogFields | None = None,
132
- ) -> PangeaResponse[TextGuardResult[_T]]:
133
- """
134
- Text Guard for scanning LLM inputs and outputs
135
-
136
- Analyze and redact text to avoid manipulation of the model, addition of
137
- malicious content, and other undesirable data transfers.
138
-
139
- OperationId: ai_guard_post_v1_text_guard
140
-
141
- Args:
142
- llm_input: Structured full llm payload data to be scanned by AI
143
- Guard for PII, sensitive data, malicious content, and other data
144
- types defined by the configuration. Supports processing up to
145
- 10KB of JSON text
146
- recipe: Recipe key of a configuration of data types and settings
147
- defined in the Pangea User Console. It specifies the rules that
148
- are to be applied to the text, such as defang malicious URLs.
149
- debug: Setting this value to true will provide a detailed analysis
150
- of the text data
151
- llm_info: Short string hint for the LLM Provider information
152
- log_field: Additional fields to include in activity log
153
-
154
- Examples:
155
- response = await ai_guard.guard_text(
156
- llm_input={"model": "gpt-4o", "messages": [{"role": "user", "content": "hello world"}]}
157
- )
158
- """
159
-
160
121
  async def guard_text( # type: ignore[misc]
161
122
  self,
162
123
  text: str | None = None,
163
124
  *,
164
125
  messages: _T | None = None,
165
- llm_input: _T | None = None,
166
126
  recipe: str | None = None,
167
127
  debug: bool | None = None,
168
- llm_info: str | None = None,
128
+ overrides: Overrides | None = None,
169
129
  log_fields: LogFields | None = None,
170
130
  ) -> PangeaResponse[TextGuardResult[None]]:
171
131
  """
@@ -184,27 +144,19 @@ class AIGuardAsync(ServiceBaseAsync):
184
144
  PII, sensitive data, malicious content, and other data types
185
145
  defined by the configuration. Supports processing up to 10KB of
186
146
  JSON text
187
- llm_input: Structured full llm payload data to be scanned by AI
188
- Guard for PII, sensitive data, malicious content, and other data
189
- types defined by the configuration. Supports processing up to
190
- 10KB of JSON text
191
147
  recipe: Recipe key of a configuration of data types and settings
192
148
  defined in the Pangea User Console. It specifies the rules that
193
149
  are to be applied to the text, such as defang malicious URLs.
194
150
  debug: Setting this value to true will provide a detailed analysis
195
151
  of the text data
196
- llm_info: Short string hint for the LLM Provider information
197
152
  log_field: Additional fields to include in activity log
198
153
 
199
154
  Examples:
200
155
  response = await ai_guard.guard_text("text")
201
156
  """
202
157
 
203
- if not any((text, messages, llm_input)):
204
- raise ValueError("Exactly one of `text`, `messages`, or `llm_input` must be given")
205
-
206
- if sum((text is not None, messages is not None, llm_input is not None)) > 1:
207
- raise ValueError("Only one of `text`, `messages`, or `llm_input` can be given at once")
158
+ if text is not None and messages is not None:
159
+ raise ValueError("Exactly one of `text` or `messages` must be given")
208
160
 
209
161
  return await self.request.post(
210
162
  "v1/text/guard",
@@ -212,10 +164,9 @@ class AIGuardAsync(ServiceBaseAsync):
212
164
  data={
213
165
  "text": text,
214
166
  "messages": messages,
215
- "llm_input": llm_input,
216
167
  "recipe": recipe,
217
168
  "debug": debug,
218
- "llm_info": llm_info,
169
+ "overrides": overrides,
219
170
  "log_fields": log_fields,
220
171
  },
221
172
  )
@@ -86,11 +86,6 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
86
86
  config = PangeaConfig(domain="pangea_domain")
87
87
  audit = AuditAsync(token="pangea_token", config=config)
88
88
  """
89
-
90
- # FIXME: Temporary check to deprecate config_id from PangeaConfig.
91
- # Delete it when deprecate PangeaConfig.config_id
92
- if config_id and config is not None and config.config_id is not None:
93
- config_id = config.config_id
94
89
  ServiceBaseAsync.__init__(self, token, config=config, logger_name=logger_name, config_id=config_id)
95
90
  AuditBase.__init__(
96
91
  self, private_key_file=private_key_file, public_key_info=public_key_info, tenant_id=tenant_id
pangea/config.py CHANGED
@@ -1,39 +1,30 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
3
4
 
4
- from dataclasses import dataclass
5
- from typing import Literal, Optional
5
+ from typing import Any, Optional
6
6
 
7
+ from pydantic import BaseModel, model_validator
7
8
 
8
- @dataclass
9
- class PangeaConfig:
10
- """Holds run time configuration information used by SDK components."""
11
-
12
- domain: str = "aws.us.pangea.cloud"
13
- """
14
- Used to set Pangea domain (and port if needed), it should not include service subdomain
15
- just for particular use cases when environment = "local", domain could be set to an url including:
16
- scheme (http:// or https://), subdomain, domain and port.
17
- """
18
-
19
- environment: Literal["production", "local"] = "production"
20
- """
21
- Pangea environment, used to construct service URLs.
22
9
 
23
- If set to "local", then `domain` must be the full host (i.e., hostname and
24
- port) for the Pangea service that this `PangeaConfig` will be used for.
25
- """
10
+ class PangeaConfig(BaseModel):
11
+ """Holds run time configuration information used by SDK components."""
26
12
 
27
- config_id: Optional[str] = None
13
+ base_url_template: str = "https://{SERVICE_NAME}.aws.us.pangea.cloud"
28
14
  """
29
- Only used for services that support multiconfig (e.g.: Audit service)
30
-
31
- @deprecated("config_id will be deprecated from PangeaConfig. Set it on service initialization instead")
15
+ Template for constructing the base URL for API requests. The placeholder
16
+ `{SERVICE_NAME}` will be replaced with the service name slug. This is a
17
+ more powerful version of `domain` that allows for setting more than just
18
+ the host of the API server. Defaults to
19
+ `https://{SERVICE_NAME}.aws.us.pangea.cloud`.
32
20
  """
33
21
 
34
- insecure: bool = False
22
+ domain: str = "aws.us.pangea.cloud"
35
23
  """
36
- Set to true to use plain http
24
+ Base domain for API requests. This is a weaker version of `base_url_template`
25
+ that only allows for setting the host of the API server. Use
26
+ `base_url_template` for more control over the URL, such as setting
27
+ service-specific paths. Defaults to `aws.us.pangea.cloud`.
37
28
  """
38
29
 
39
30
  request_retries: int = 3
@@ -65,3 +56,10 @@ class PangeaConfig:
65
56
  """
66
57
  Extra user agent to be added to request user agent
67
58
  """
59
+
60
+ @model_validator(mode="before")
61
+ @classmethod
62
+ def _domain_backwards_compat(cls, data: Any) -> Any:
63
+ if isinstance(data, dict) and "base_url_template" not in data and "domain" in data:
64
+ return {**data, "base_url_template": f"https://{{SERVICE_NAME}}.{data['domain']}"}
65
+ return data
pangea/request.py CHANGED
@@ -14,6 +14,7 @@ from pydantic_core import to_jsonable_python
14
14
  from requests.adapters import HTTPAdapter, Retry
15
15
  from requests_toolbelt import MultipartDecoder # type: ignore[import-untyped]
16
16
  from typing_extensions import TypeVar
17
+ from yarl import URL
17
18
 
18
19
  import pangea
19
20
  import pangea.exceptions as pe
@@ -107,16 +108,8 @@ class PangeaRequestBase:
107
108
  return f"request/{request_id}"
108
109
 
109
110
  def _url(self, path: str) -> str:
110
- if self.config.domain.startswith("http://") or self.config.domain.startswith("https://"):
111
- # it's URL
112
- url = f"{self.config.domain}/{path}"
113
- else:
114
- schema = "http://" if self.config.insecure else "https://"
115
- domain = (
116
- self.config.domain if self.config.environment == "local" else f"{self.service}.{self.config.domain}"
117
- )
118
- url = f"{schema}{domain}/{path}"
119
- return url
111
+ url = URL(self.config.base_url_template.format(SERVICE_NAME=self.service))
112
+ return str(url / path)
120
113
 
121
114
  def _headers(self) -> dict:
122
115
  headers = {
@@ -124,7 +117,7 @@ class PangeaRequestBase:
124
117
  "Authorization": f"Bearer {self.token}",
125
118
  }
126
119
 
127
- # We want to ignore previous headers if user tryed to set them, so we will overwrite them.
120
+ # We want to ignore previous headers if user tried to set them, so we will overwrite them.
128
121
  self._extra_headers.update(headers)
129
122
  return self._extra_headers
130
123
 
@@ -628,9 +621,7 @@ class PangeaRequest(PangeaRequestBase):
628
621
  adapter = HTTPAdapter(max_retries=retry_config)
629
622
  session = requests.Session()
630
623
 
631
- if self.config.insecure:
632
- session.mount("http://", adapter)
633
- else:
634
- session.mount("https://", adapter)
624
+ session.mount("http://", adapter)
625
+ session.mount("https://", adapter)
635
626
 
636
627
  return session
@@ -1,11 +1,155 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Dict, Generic, List, Optional, TypeVar, overload
3
+ from typing import Any, Dict, Generic, List, Literal, Optional, TypeVar, overload
4
4
 
5
5
  from pangea.config import PangeaConfig
6
6
  from pangea.response import APIRequestModel, APIResponseModel, PangeaResponse, PangeaResponseResult
7
7
  from pangea.services.base import ServiceBase
8
8
 
9
+ # This is named "prompt injection" in the API spec even though it is also used
10
+ # for many other detectors.
11
+ PromptInjectionAction = Literal["report", "block"]
12
+
13
+ MaliciousEntityAction = Literal["report", "defang", "disabled", "block"]
14
+
15
+ # This is named "PII entity" in the API spec even though it is also used for the
16
+ # secrets detector.
17
+ PiiEntityAction = Literal["disabled", "report", "block", "mask", "partial_masking", "replacement", "hash", "fpe"]
18
+
19
+
20
+ class CodeDetectionOverride(APIRequestModel):
21
+ disabled: Optional[bool] = None
22
+ action: Optional[Literal["report", "block"]] = None
23
+
24
+
25
+ class LanguageDetectionOverride(APIRequestModel):
26
+ disabled: Optional[bool] = None
27
+ allow: Optional[List[str]] = None
28
+ block: Optional[List[str]] = None
29
+ report: Optional[List[str]] = None
30
+
31
+
32
+ class TopicDetectionOverride(APIRequestModel):
33
+ disabled: Optional[bool] = None
34
+ block: Optional[List[str]] = None
35
+
36
+
37
+ class PromptInjectionOverride(APIRequestModel):
38
+ disabled: Optional[bool] = None
39
+ action: Optional[PromptInjectionAction] = None
40
+
41
+
42
+ class SelfHarmOverride(APIRequestModel):
43
+ disabled: Optional[bool] = None
44
+ action: Optional[PromptInjectionAction] = None
45
+ threshold: Optional[float] = None
46
+
47
+
48
+ class GibberishOverride(APIRequestModel):
49
+ disabled: Optional[bool] = None
50
+ action: Optional[PromptInjectionAction] = None
51
+
52
+
53
+ class RoleplayOverride(APIRequestModel):
54
+ disabled: Optional[bool] = None
55
+ action: Optional[PromptInjectionAction] = None
56
+
57
+
58
+ class SentimentOverride(APIRequestModel):
59
+ disabled: Optional[bool] = None
60
+ action: Optional[PromptInjectionAction] = None
61
+ threshold: Optional[float] = None
62
+
63
+
64
+ class MaliciousEntityOverride(APIRequestModel):
65
+ disabled: Optional[bool] = None
66
+ ip_address: Optional[MaliciousEntityAction] = None
67
+ url: Optional[MaliciousEntityAction] = None
68
+ domain: Optional[MaliciousEntityAction] = None
69
+
70
+
71
+ class CompetitorsOverride(APIRequestModel):
72
+ disabled: Optional[bool] = None
73
+ action: Optional[PromptInjectionAction] = None
74
+
75
+
76
+ class PiiEntityOverride(APIRequestModel):
77
+ disabled: Optional[bool] = None
78
+ email_address: Optional[PiiEntityAction] = None
79
+ nrp: Optional[PiiEntityAction] = None
80
+ location: Optional[PiiEntityAction] = None
81
+ person: Optional[PiiEntityAction] = None
82
+ phone_number: Optional[PiiEntityAction] = None
83
+ date_time: Optional[PiiEntityAction] = None
84
+ ip_address: Optional[PiiEntityAction] = None
85
+ url: Optional[PiiEntityAction] = None
86
+ money: Optional[PiiEntityAction] = None
87
+ credit_card: Optional[PiiEntityAction] = None
88
+ crypto: Optional[PiiEntityAction] = None
89
+ iban_code: Optional[PiiEntityAction] = None
90
+ us_bank_number: Optional[PiiEntityAction] = None
91
+ nif: Optional[PiiEntityAction] = None
92
+ au_abn: Optional[PiiEntityAction] = None
93
+ au_acn: Optional[PiiEntityAction] = None
94
+ au_tfn: Optional[PiiEntityAction] = None
95
+ medical_license: Optional[PiiEntityAction] = None
96
+ uk_nhs: Optional[PiiEntityAction] = None
97
+ au_medicare: Optional[PiiEntityAction] = None
98
+ us_drivers_license: Optional[PiiEntityAction] = None
99
+ us_itin: Optional[PiiEntityAction] = None
100
+ us_passport: Optional[PiiEntityAction] = None
101
+ us_ssn: Optional[PiiEntityAction] = None
102
+
103
+
104
+ class SecretsDetectionOverride(APIRequestModel):
105
+ disabled: Optional[bool] = None
106
+ slack_token: Optional[PiiEntityAction] = None
107
+ rsa_private_key: Optional[PiiEntityAction] = None
108
+ ssh_dsa_private_key: Optional[PiiEntityAction] = None
109
+ ssh_ec_private_key: Optional[PiiEntityAction] = None
110
+ pgp_private_key_block: Optional[PiiEntityAction] = None
111
+ amazon_aws_access_key_id: Optional[PiiEntityAction] = None
112
+ amazon_aws_secret_access_key: Optional[PiiEntityAction] = None
113
+ amazon_mws_auth_token: Optional[PiiEntityAction] = None
114
+ facebook_access_token: Optional[PiiEntityAction] = None
115
+ github_access_token: Optional[PiiEntityAction] = None
116
+ jwt_token: Optional[PiiEntityAction] = None
117
+ google_api_key: Optional[PiiEntityAction] = None
118
+ google_cloud_platform_api_key: Optional[PiiEntityAction] = None
119
+ google_drive_api_key: Optional[PiiEntityAction] = None
120
+ google_cloud_platform_service_account: Optional[PiiEntityAction] = None
121
+ google_gmail_api_key: Optional[PiiEntityAction] = None
122
+ youtube_api_key: Optional[PiiEntityAction] = None
123
+ mailchimp_api_key: Optional[PiiEntityAction] = None
124
+ mailgun_api_key: Optional[PiiEntityAction] = None
125
+ basic_auth: Optional[PiiEntityAction] = None
126
+ picatic_api_key: Optional[PiiEntityAction] = None
127
+ slack_webhook: Optional[PiiEntityAction] = None
128
+ stripe_api_key: Optional[PiiEntityAction] = None
129
+ stripe_restricted_api_key: Optional[PiiEntityAction] = None
130
+ square_access_token: Optional[PiiEntityAction] = None
131
+ square_oauth_secret: Optional[PiiEntityAction] = None
132
+ twilio_api_key: Optional[PiiEntityAction] = None
133
+ pangea_token: Optional[PiiEntityAction] = None
134
+
135
+
136
+ class Overrides(APIRequestModel):
137
+ ignore_recipe: Optional[bool] = None
138
+ """Bypass existing Recipe content and create an on-the-fly Recipe."""
139
+
140
+ code_detection: Optional[CodeDetectionOverride] = None
141
+ competitors: Optional[CompetitorsOverride] = None
142
+ gibberish: Optional[GibberishOverride] = None
143
+ language_detection: Optional[LanguageDetectionOverride] = None
144
+ malicious_entity: Optional[MaliciousEntityOverride] = None
145
+ pii_entity: Optional[PiiEntityOverride] = None
146
+ prompt_injection: Optional[PromptInjectionOverride] = None
147
+ roleplay: Optional[RoleplayOverride] = None
148
+ secrets_detection: Optional[SecretsDetectionOverride] = None
149
+ selfharm: Optional[SelfHarmOverride] = None
150
+ sentiment: Optional[SentimentOverride] = None
151
+ topic_detection: Optional[TopicDetectionOverride] = None
152
+
9
153
 
10
154
  class LogFields(APIRequestModel):
11
155
  """Additional fields to include in activity log"""
@@ -33,6 +177,8 @@ class AnalyzerResponse(APIResponseModel):
33
177
 
34
178
  class PromptInjectionResult(APIResponseModel):
35
179
  action: str
180
+ """The action taken by this Detector"""
181
+
36
182
  analyzer_responses: List[AnalyzerResponse]
37
183
  """Triggered prompt injection analyzers."""
38
184
 
@@ -41,11 +187,13 @@ class PiiEntity(APIResponseModel):
41
187
  type: str
42
188
  value: str
43
189
  action: str
190
+ """The action taken on this Entity"""
44
191
  start_pos: Optional[int] = None
45
192
 
46
193
 
47
194
  class PiiEntityResult(APIResponseModel):
48
195
  entities: List[PiiEntity]
196
+ """Detected redaction rules."""
49
197
 
50
198
 
51
199
  class MaliciousEntity(APIResponseModel):
@@ -58,35 +206,59 @@ class MaliciousEntity(APIResponseModel):
58
206
 
59
207
  class MaliciousEntityResult(APIResponseModel):
60
208
  entities: List[MaliciousEntity]
209
+ """Detected harmful items."""
210
+
211
+
212
+ class CustomEntity(APIResponseModel):
213
+ type: str
214
+ value: str
215
+ action: str
216
+ """The action taken on this Entity"""
217
+ start_pos: Optional[int] = None
218
+ raw: Optional[Dict[str, Any]] = None
219
+
220
+
221
+ class CustomEntityResult(APIResponseModel):
222
+ entities: List[CustomEntity]
223
+ """Detected redaction rules."""
61
224
 
62
225
 
63
226
  class SecretsEntity(APIResponseModel):
64
227
  type: str
65
228
  value: str
66
229
  action: str
230
+ """The action taken on this Entity"""
67
231
  start_pos: Optional[int] = None
68
232
  redacted_value: Optional[str] = None
69
233
 
70
234
 
71
235
  class SecretsEntityResult(APIResponseModel):
72
236
  entities: List[SecretsEntity]
237
+ """Detected redaction rules."""
73
238
 
74
239
 
75
240
  class LanguageDetectionResult(APIResponseModel):
76
241
  language: str
77
242
  action: str
243
+ """The action taken by this Detector"""
244
+
245
+
246
+ class TopicDetectionResult(APIResponseModel):
247
+ action: str
248
+ """The action taken by this Detector"""
78
249
 
79
250
 
80
251
  class CodeDetectionResult(APIResponseModel):
81
252
  language: str
82
253
  action: str
254
+ """The action taken by this Detector"""
83
255
 
84
256
 
85
257
  _T = TypeVar("_T")
86
258
 
87
259
 
88
260
  class TextGuardDetector(APIResponseModel, Generic[_T]):
89
- detected: bool
261
+ detected: Optional[bool] = None
90
262
  data: Optional[_T] = None
91
263
 
92
264
 
@@ -94,10 +266,11 @@ class TextGuardDetectors(APIResponseModel):
94
266
  prompt_injection: Optional[TextGuardDetector[PromptInjectionResult]] = None
95
267
  pii_entity: Optional[TextGuardDetector[PiiEntityResult]] = None
96
268
  malicious_entity: Optional[TextGuardDetector[MaliciousEntityResult]] = None
269
+ custom_entity: Optional[TextGuardDetector[Any]] = None
97
270
  secrets_detection: Optional[TextGuardDetector[SecretsEntityResult]] = None
98
271
  profanity_and_toxicity: Optional[TextGuardDetector[Any]] = None
99
- custom_entity: Optional[TextGuardDetector[Any]] = None
100
272
  language_detection: Optional[TextGuardDetector[LanguageDetectionResult]] = None
273
+ topic_detection: Optional[TextGuardDetector[TopicDetectionResult]] = None
101
274
  code_detection: Optional[TextGuardDetector[CodeDetectionResult]] = None
102
275
 
103
276
 
@@ -112,6 +285,16 @@ class TextGuardResult(PangeaResponseResult, Generic[_T]):
112
285
  """Updated structured prompt, if applicable."""
113
286
 
114
287
  blocked: bool
288
+ """Whether or not the prompt triggered a block detection."""
289
+
290
+ recipe: str
291
+ """The Recipe that was used."""
292
+
293
+ fpe_context: Optional[str] = None
294
+ """
295
+ If an FPE redaction method returned results, this will be the context passed
296
+ to unredact.
297
+ """
115
298
 
116
299
 
117
300
  class AIGuard(ServiceBase):
@@ -160,7 +343,7 @@ class AIGuard(ServiceBase):
160
343
  *,
161
344
  recipe: str | None = None,
162
345
  debug: bool | None = None,
163
- llm_info: str | None = None,
346
+ overrides: Overrides | None = None,
164
347
  log_fields: LogFields | None = None,
165
348
  ) -> PangeaResponse[TextGuardResult[None]]:
166
349
  """
@@ -180,7 +363,6 @@ class AIGuard(ServiceBase):
180
363
  are to be applied to the text, such as defang malicious URLs.
181
364
  debug: Setting this value to true will provide a detailed analysis
182
365
  of the text data
183
- llm_info: Short string hint for the LLM Provider information
184
366
  log_field: Additional fields to include in activity log
185
367
 
186
368
  Examples:
@@ -194,7 +376,7 @@ class AIGuard(ServiceBase):
194
376
  messages: _T,
195
377
  recipe: str | None = None,
196
378
  debug: bool | None = None,
197
- llm_info: str | None = None,
379
+ overrides: Overrides | None = None,
198
380
  log_fields: LogFields | None = None,
199
381
  ) -> PangeaResponse[TextGuardResult[_T]]:
200
382
  """
@@ -215,59 +397,20 @@ class AIGuard(ServiceBase):
215
397
  are to be applied to the text, such as defang malicious URLs.
216
398
  debug: Setting this value to true will provide a detailed analysis
217
399
  of the text data
218
- llm_info: Short string hint for the LLM Provider information
219
400
  log_field: Additional fields to include in activity log
220
401
 
221
402
  Examples:
222
403
  response = ai_guard.guard_text(messages=[{"role": "user", "content": "hello world"}])
223
404
  """
224
405
 
225
- @overload
226
- def guard_text(
227
- self,
228
- *,
229
- llm_input: _T,
230
- recipe: str | None = None,
231
- debug: bool | None = None,
232
- llm_info: str | None = None,
233
- log_fields: LogFields | None = None,
234
- ) -> PangeaResponse[TextGuardResult[_T]]:
235
- """
236
- Text Guard for scanning LLM inputs and outputs
237
-
238
- Analyze and redact text to avoid manipulation of the model, addition of
239
- malicious content, and other undesirable data transfers.
240
-
241
- OperationId: ai_guard_post_v1_text_guard
242
-
243
- Args:
244
- llm_input: Structured full llm payload data to be scanned by AI
245
- Guard for PII, sensitive data, malicious content, and other data
246
- types defined by the configuration. Supports processing up to
247
- 10KB of JSON text
248
- recipe: Recipe key of a configuration of data types and settings
249
- defined in the Pangea User Console. It specifies the rules that
250
- are to be applied to the text, such as defang malicious URLs.
251
- debug: Setting this value to true will provide a detailed analysis
252
- of the text data
253
- llm_info: Short string hint for the LLM Provider information
254
- log_field: Additional fields to include in activity log
255
-
256
- Examples:
257
- response = ai_guard.guard_text(
258
- llm_input={"model": "gpt-4o", "messages": [{"role": "user", "content": "hello world"}]}
259
- )
260
- """
261
-
262
406
  def guard_text( # type: ignore[misc]
263
407
  self,
264
408
  text: str | None = None,
265
409
  *,
266
410
  messages: _T | None = None,
267
- llm_input: _T | None = None,
268
411
  recipe: str | None = None,
269
412
  debug: bool | None = None,
270
- llm_info: str | None = None,
413
+ overrides: Overrides | None = None,
271
414
  log_fields: LogFields | None = None,
272
415
  ) -> PangeaResponse[TextGuardResult[None]]:
273
416
  """
@@ -286,27 +429,19 @@ class AIGuard(ServiceBase):
286
429
  PII, sensitive data, malicious content, and other data types
287
430
  defined by the configuration. Supports processing up to 10KB of
288
431
  JSON text
289
- llm_input: Structured full llm payload data to be scanned by AI
290
- Guard for PII, sensitive data, malicious content, and other data
291
- types defined by the configuration. Supports processing up to
292
- 10KB of JSON text
293
432
  recipe: Recipe key of a configuration of data types and settings
294
433
  defined in the Pangea User Console. It specifies the rules that
295
434
  are to be applied to the text, such as defang malicious URLs.
296
435
  debug: Setting this value to true will provide a detailed analysis
297
436
  of the text data
298
- llm_info: Short string hint for the LLM Provider information
299
437
  log_field: Additional fields to include in activity log
300
438
 
301
439
  Examples:
302
440
  response = ai_guard.guard_text("text")
303
441
  """
304
442
 
305
- if not any((text, messages, llm_input)):
306
- raise ValueError("At least one of `text`, `messages`, or `llm_input` must be given")
307
-
308
- if sum((text is not None, messages is not None, llm_input is not None)) > 1:
309
- raise ValueError("Only one of `text`, `messages`, or `llm_input` can be given at once")
443
+ if text is not None and messages is not None:
444
+ raise ValueError("Exactly one of `text` or `messages` must be given")
310
445
 
311
446
  return self.request.post(
312
447
  "v1/text/guard",
@@ -314,10 +449,9 @@ class AIGuard(ServiceBase):
314
449
  data={
315
450
  "text": text,
316
451
  "messages": messages,
317
- "llm_input": llm_input,
318
452
  "recipe": recipe,
319
453
  "debug": debug,
320
- "llm_info": llm_info,
454
+ "overrides": overrides,
321
455
  "log_fields": log_fields,
322
456
  },
323
457
  )
@@ -408,10 +408,6 @@ class Audit(ServiceBase, AuditBase):
408
408
  config = PangeaConfig(domain="pangea_domain")
409
409
  audit = Audit(token="pangea_token", config=config)
410
410
  """
411
- # FIXME: Temporary check to deprecate config_id from PangeaConfig.
412
- # Delete it when deprecate PangeaConfig.config_id
413
- if config_id and config is not None and config.config_id is not None:
414
- config_id = config.config_id
415
411
  ServiceBase.__init__(self, token, config=config, logger_name=logger_name, config_id=config_id)
416
412
  AuditBase.__init__(
417
413
  self, private_key_file=private_key_file, public_key_info=public_key_info, tenant_id=tenant_id
@@ -36,8 +36,8 @@ class GuardResult(PangeaResponseResult):
36
36
  analyzer: Optional[str] = None
37
37
  """Prompt Analyzers for identifying and rejecting properties of prompts"""
38
38
 
39
- confidence: int
40
- """Percent of confidence in the detection result, ranging from 0 to 100"""
39
+ confidence: float
40
+ """Percent of confidence in the detection result, ranging from 0 to 1"""
41
41
 
42
42
  info: Optional[str] = None
43
43
  """Extra information about the detection result"""
pangea/services/redact.py CHANGED
@@ -155,12 +155,19 @@ class StructuredRequest(APIRequestModel):
155
155
  class StructuredResult(PangeaResponseResult):
156
156
  """
157
157
  Result class after a structured redact request
158
-
159
158
  """
160
159
 
161
160
  redacted_data: Optional[Union[Dict, str]] = None
161
+ """Redacted data result"""
162
+
162
163
  count: int
164
+ """Number of redactions present in the text"""
165
+
163
166
  report: Optional[DebugReport] = None
167
+ """Describes the decision process for redactions"""
168
+
169
+ fpe_context: Optional[str] = None
170
+ """FPE context used to encrypt and redact data"""
164
171
 
165
172
 
166
173
  class UnredactRequest(APIRequestModel):
@@ -170,7 +177,6 @@ class UnredactRequest(APIRequestModel):
170
177
  Arguments:
171
178
  redacted_data: Data to unredact
172
179
  fpe_context (base64): FPE context used to decrypt and unredact data
173
-
174
180
  """
175
181
 
176
182
  redacted_data: RedactedData
@@ -183,7 +189,6 @@ RedactedData = Union[str, Dict]
183
189
  class UnredactResult(PangeaResponseResult):
184
190
  """
185
191
  Result class after an unredact request
186
-
187
192
  """
188
193
 
189
194
  data: RedactedData
pangea/tools.py CHANGED
@@ -151,20 +151,17 @@ def get_config_id(environment: TestEnvironment, service: str, config_number: int
151
151
 
152
152
  def get_custom_schema_test_token(environment: TestEnvironment):
153
153
  env_var_name = f"PANGEA_INTEGRATION_CUSTOM_SCHEMA_TOKEN_{environment}"
154
- value = os.getenv(env_var_name)
155
- if not value:
156
- raise PangeaException(f"{env_var_name} env var need to be set")
157
-
158
- return value
154
+ return _load_env_var(env_var_name)
159
155
 
160
156
 
161
157
  def get_custom_schema_vault_test_token(environment: TestEnvironment):
162
158
  env_var_name = f"PANGEA_INTEGRATION_CUSTOM_SCHEMA_TOKEN_{environment}"
163
- value = os.getenv(env_var_name)
164
- if not value:
165
- raise PangeaException(f"{env_var_name} env var need to be set")
159
+ return _load_env_var(env_var_name)
166
160
 
167
- return value
161
+
162
+ def get_vault_fpe_key_id(environment: TestEnvironment):
163
+ env_var_name = f"PANGEA_INTEGRATION_FPE_KEY_ID_{environment}"
164
+ return _load_env_var(env_var_name)
168
165
 
169
166
 
170
167
  class SequenceFollower:
@@ -1,23 +1,24 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pangea-sdk
3
- Version: 5.5.0b4
3
+ Version: 6.0.0
4
4
  Summary: Pangea API SDK
5
5
  License: MIT
6
6
  Keywords: Pangea,SDK,Audit
7
7
  Author: Glenn Gallien
8
8
  Author-email: glenn.gallien@pangea.cloud
9
- Requires-Python: >=3.9,<4.0.0
9
+ Requires-Python: >=3.9.2,<4.0.0
10
10
  Classifier: Topic :: Software Development
11
11
  Classifier: Topic :: Software Development :: Libraries
12
- Requires-Dist: aiohttp (>=3.11.11,<4.0.0)
13
- Requires-Dist: cryptography (>=43.0.3,<44.0.0)
12
+ Requires-Dist: aiohttp (>=3.11.16,<4.0.0)
13
+ Requires-Dist: cryptography (>=44.0.2,<44.0.3)
14
14
  Requires-Dist: deprecated (>=1.2.18,<2.0.0)
15
- Requires-Dist: google-crc32c (>=1.6.0,<2.0.0)
16
- Requires-Dist: pydantic (>=2.10.6,<3.0.0)
15
+ Requires-Dist: google-crc32c (>=1.7.1,<2.0.0)
16
+ Requires-Dist: pydantic (>=2.11.3,<3.0.0)
17
17
  Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
18
18
  Requires-Dist: requests (>=2.32.3,<3.0.0)
19
19
  Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
20
- Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
20
+ Requires-Dist: typing-extensions (>=4.13.2,<5.0.0)
21
+ Requires-Dist: yarl (>=1.20.0,<2.0.0)
21
22
  Description-Content-Type: text/markdown
22
23
 
23
24
  <a href="https://pangea.cloud?utm_source=github&utm_medium=python-sdk" target="_blank" rel="noopener noreferrer">
@@ -26,12 +27,11 @@ Description-Content-Type: text/markdown
26
27
 
27
28
  <br />
28
29
 
29
- [![documentation](https://img.shields.io/badge/documentation-pangea-blue?style=for-the-badge&labelColor=551B76)][Documentation]
30
- [![Discourse](https://img.shields.io/badge/Discourse-4A154B?style=for-the-badge&logo=discourse&logoColor=white)][Discourse]
30
+ [![Documentation](https://img.shields.io/badge/documentation-pangea-blue?style=for-the-badge&labelColor=551B76)][Documentation]
31
31
 
32
32
  # Pangea Python SDK
33
33
 
34
- A Python SDK for integrating with Pangea services. Supports Python v3.9 and
34
+ A Python SDK for integrating with Pangea services. Supports Python v3.9.2 and
35
35
  above.
36
36
 
37
37
  ## Installation
@@ -63,13 +63,13 @@ the same compatibility guarantees as stable releases.
63
63
  Via pip:
64
64
 
65
65
  ```bash
66
- $ pip3 install pangea-sdk==5.5.0b4
66
+ $ pip3 install pangea-sdk==5.5.0b2
67
67
  ```
68
68
 
69
69
  Via poetry:
70
70
 
71
71
  ```bash
72
- $ poetry add pangea-sdk==5.5.0b4
72
+ $ poetry add pangea-sdk==5.5.0b2
73
73
  ```
74
74
 
75
75
  ## Usage
@@ -223,6 +223,5 @@ It accepts multiple file formats:
223
223
  [GA Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
224
224
  [Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
225
225
  [Pangea Console]: https://console.pangea.cloud/
226
- [Discourse]: https://l.pangea.cloud/Jd4wlGs
227
226
  [Secure Audit Log]: https://pangea.cloud/docs/audit
228
227
 
@@ -1,10 +1,10 @@
1
- pangea/__init__.py,sha256=fCxvmybvVb3077qDVFJbBz4QSz5gOCC6lb36iuU2BxY,251
1
+ pangea/__init__.py,sha256=WlZa15dkqzwfQrtPRyiGS0sYP9wBJcaBvWFl_kcNUjs,246
2
2
  pangea/asyncio/__init__.py,sha256=kjEMkqMQ521LlMSu5jn3_WgweyArwVZ2C-s3x7mR6Pk,45
3
3
  pangea/asyncio/file_uploader.py,sha256=wI7epib7Rc5jtZw4eJ1L1SlmutDG6CPv59C8N2UPhtY,1436
4
4
  pangea/asyncio/request.py,sha256=lpLY-o405r3-VUfrAE5uxYxI8UjM4hjPqUzAUtOGE5o,18040
5
5
  pangea/asyncio/services/__init__.py,sha256=L6Tdhjfx_ZECHskhLMPaCcOefi-r-imw6q_zlU4j-FY,464
6
- pangea/asyncio/services/ai_guard.py,sha256=Q_Q_1xKvxXsW6jHsEDjPVHAOYYvz7bmulC5480vRc-s,8541
7
- pangea/asyncio/services/audit.py,sha256=rPaCx4cMzj-g9WFMRIysFCJAz6Btp6YrhcKe_exky8k,26283
6
+ pangea/asyncio/services/ai_guard.py,sha256=rFksT8LQkyioW3QOq4fLCEZbW5SXiYWpWjLbVovRouE,6294
7
+ pangea/asyncio/services/audit.py,sha256=Ue3KDmTn-a2KsqlzxbakLQJAWiRyLaJrYVi1hO7a6sw,26030
8
8
  pangea/asyncio/services/authn.py,sha256=rPeLJweL8mYH_t4ebcQn4n_Wglr3kClKNnCXNCimZU4,46622
9
9
  pangea/asyncio/services/authz.py,sha256=B_0_nhDMJcjNpjpCx3Vi2LDRhlmfV9325GKbUZ8reos,10025
10
10
  pangea/asyncio/services/base.py,sha256=vRFVcO_uEAGJte3OUUBLD43RoiiFB1vC7SPyN6yEMoA,3158
@@ -17,7 +17,7 @@ pangea/asyncio/services/sanitize.py,sha256=EbSdq_v9yZWce9xEYWvZharE9bJcxw8cg5Pv8
17
17
  pangea/asyncio/services/share.py,sha256=Qd2Oh4UsLwu7Zo4Xy1KABHuP4TJ9AtcN-XzldvilFVo,30773
18
18
  pangea/asyncio/services/vault.py,sha256=VqrJGSEdq6MlZRI6cJpkthhIsqLClSQdgVxwYCbIwEk,77079
19
19
  pangea/audit_logger.py,sha256=gRkCfUUT5LDNaycwxkhZUySgY47jDfn1ZeKOul4XCQI,3842
20
- pangea/config.py,sha256=qe1ZhvDxNQxNXUpAtzF6nPLjyRpPVG9sjhLZV6Pkyn8,1766
20
+ pangea/config.py,sha256=Z2WT_UG0qBQzzVzBfloXYFxS21mSg1YXQ36cAVCqrJk,1963
21
21
  pangea/crypto/rsa.py,sha256=mwSiNy571KAGr3F6oEM0CXWkl9D023ch8ldbZZeLj_4,4747
22
22
  pangea/deep_verify.py,sha256=ZGraaL7TCxwRBIDqjBFR0clKlhAC-Yce6kD-1LClhG8,8616
23
23
  pangea/deprecated.py,sha256=IjFYEVvY1E0ld0SMkEYC1o62MAleX3nnT1If2dFVbHo,608
@@ -25,11 +25,11 @@ pangea/dump_audit.py,sha256=IevqaUUh7GDepdIW7slSxeZbkPrWIVbcX3sr4DgpJXI,7090
25
25
  pangea/exceptions.py,sha256=OBtzUECpNa6vNp8ySkHC-tm4QjFRCOAHBkMHqzAlOu8,5656
26
26
  pangea/file_uploader.py,sha256=4RQ44xt-faApC61nn2PlwHT7XYrJ4GeQA8Ug4tySEAg,1227
27
27
  pangea/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- pangea/request.py,sha256=vGB8owXUiNQoeiiACFvfXvg44JJo_L6WfcHlF6ug8co,25082
28
+ pangea/request.py,sha256=4ZVD1F3CS4XdLM45vfhlCazZ5NQF1jUzu4j31yjH3KE,24689
29
29
  pangea/response.py,sha256=lPAcYsF9Xg166CiyhCofVmQA-W4jevh0MQXxUa8Re68,7737
30
30
  pangea/services/__init__.py,sha256=h36HzyIGaI5kO6l3UCwKHx_Kd-m_9mYVwn5MLRVzblI,408
31
- pangea/services/ai_guard.py,sha256=tBr3GEbrobjECs51cRR63Q8AICMl-K3tQD1FdyZkR4s,11129
32
- pangea/services/audit/audit.py,sha256=7-c9l7jyGtpG7SqRUMpqsAzcUDhMZ5izgPalxHXsUvM,39320
31
+ pangea/services/ai_guard.py,sha256=X1DR1JTYZnLqBFFAHgmRk4xqyGF3GQMO1B3_cqLLVfU,15774
32
+ pangea/services/audit/audit.py,sha256=TbDiO5eAHWCWAynQ4PChonTEN7z7ehZaR-duxbIFZ6Q,39068
33
33
  pangea/services/audit/exceptions.py,sha256=bhVuYe4ammacOVxwg98CChxvwZf5FKgR2DcgqILOcwc,471
34
34
  pangea/services/audit/models.py,sha256=1h1B9eSYQMYG3f8WNi1UcDX2-impRrET_ErjJYUnj7M,14678
35
35
  pangea/services/audit/signing.py,sha256=5A4hvPtpfP2kMz8bsiiKUACriXbh5dv9gb_rbqiUtuI,5583
@@ -41,8 +41,8 @@ pangea/services/base.py,sha256=43pWQcR9CeT4sGzgctF3Sy4M_h7DaUzkuZD2Z7CcDUU,3845
41
41
  pangea/services/embargo.py,sha256=9Wfku4td5ORaIENKmnGmS5jxJJIRfWp6Q51L36Jsy0I,3897
42
42
  pangea/services/file_scan.py,sha256=QiO80uKqB_BnAOiYQKznXfxpa5j40qqETE3-zBRT_QE,7813
43
43
  pangea/services/intel.py,sha256=y1EX2ctYIxQc52lmHp6-Q_UIDM--t3fOpXDssWiRPfo,56474
44
- pangea/services/prompt_guard.py,sha256=uMpofGKltmlNklF8znhRLuY6siyjDf-Zw-4Hwy2oJtc,3446
45
- pangea/services/redact.py,sha256=ovIcT0jkXe57O7keGzSClWNCic8y-4NZoemXoSKjjww,12913
44
+ pangea/services/prompt_guard.py,sha256=Cq8ume2_YPfHre4iN6FYkyTV7NrdwLXlr_wnilfKotE,3446
45
+ pangea/services/redact.py,sha256=ZTZgx3w4X923ZjWcBpI4c0gVh9cpJpcUpWuTNVVuHeY,13143
46
46
  pangea/services/sanitize.py,sha256=eAN1HhObiKqygy6HHcfl0NmxYfPMvqSKepwEAVVIIEE,12936
47
47
  pangea/services/share/file_format.py,sha256=1svO1ee_aenA9zoO_AaU-Rk5Ulp7kcPOc_KwNoluyQE,2797
48
48
  pangea/services/share/share.py,sha256=hlhkIr6ScJ5oMFUs9no4HtHNoUEbYU4KoLkiGLxex30,52343
@@ -52,9 +52,9 @@ pangea/services/vault/models/keys.py,sha256=duAuTiOby_D7MloRvN4gNj0P-b-jx9sdtplA
52
52
  pangea/services/vault/models/secret.py,sha256=ItGdkulM-SEySfcm4a5yGxMvo_omjC7kChv6gdbFnn8,1142
53
53
  pangea/services/vault/models/symmetric.py,sha256=t8xCM1wGGKDBpOqTggFueO4-4-2IFmyxqcs7_PDr7U0,2562
54
54
  pangea/services/vault/vault.py,sha256=ow-Zm7PYzfWIfUcA4UNnpeL2DHfZM4C7inRDmNR3zQU,76196
55
- pangea/tools.py,sha256=2-Y4SAHWFv6Ocj42J_bWrVy27M5G3wi7a8LJn0dabHc,6427
55
+ pangea/tools.py,sha256=icHduOfZLi02UYdGb5Xl1fQqu-PBRB4tiDPT_nL2Q8E,6380
56
56
  pangea/utils.py,sha256=dZ6MwFVEWXUgXvvDg-k6JnvVfsgslvtaBd7ez7afrqk,4983
57
57
  pangea/verify_audit.py,sha256=nSP17OzoSPdvezRExwfcf45H8ZPZnxZu-CbEp3qFJO0,17354
58
- pangea_sdk-5.5.0b4.dist-info/METADATA,sha256=KtUZWuQgJVjZipQZ77PbZw33faRG6M_425ZGLxvxCA4,7017
59
- pangea_sdk-5.5.0b4.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
60
- pangea_sdk-5.5.0b4.dist-info/RECORD,,
58
+ pangea_sdk-6.0.0.dist-info/METADATA,sha256=X9QYxYoEw53LK2rdWTOvEs9I24--d27P7Xeft4DTGzM,6886
59
+ pangea_sdk-6.0.0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
60
+ pangea_sdk-6.0.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.0.1
2
+ Generator: poetry-core 2.1.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any