pangea-sdk 6.1.1__py3-none-any.whl → 6.2.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. pangea/__init__.py +9 -1
  2. pangea/asyncio/__init__.py +1 -0
  3. pangea/asyncio/file_uploader.py +4 -2
  4. pangea/asyncio/request.py +199 -35
  5. pangea/asyncio/services/__init__.py +3 -0
  6. pangea/asyncio/services/ai_guard.py +91 -2
  7. pangea/asyncio/services/audit.py +307 -2
  8. pangea/asyncio/services/authn.py +12 -2
  9. pangea/asyncio/services/base.py +4 -0
  10. pangea/asyncio/services/file_scan.py +7 -1
  11. pangea/asyncio/services/intel.py +6 -2
  12. pangea/asyncio/services/management.py +576 -0
  13. pangea/asyncio/services/prompt_guard.py +112 -2
  14. pangea/asyncio/services/redact.py +269 -4
  15. pangea/asyncio/services/sanitize.py +5 -1
  16. pangea/asyncio/services/share.py +5 -1
  17. pangea/asyncio/services/vault.py +4 -0
  18. pangea/audit_logger.py +3 -1
  19. pangea/deep_verify.py +13 -13
  20. pangea/deprecated.py +1 -1
  21. pangea/dump_audit.py +2 -3
  22. pangea/exceptions.py +8 -5
  23. pangea/file_uploader.py +4 -0
  24. pangea/request.py +205 -52
  25. pangea/response.py +15 -12
  26. pangea/services/__init__.py +3 -0
  27. pangea/services/ai_guard.py +497 -16
  28. pangea/services/audit/audit.py +310 -8
  29. pangea/services/audit/models.py +279 -0
  30. pangea/services/audit/signing.py +1 -1
  31. pangea/services/audit/util.py +10 -10
  32. pangea/services/authn/authn.py +12 -2
  33. pangea/services/authn/models.py +3 -0
  34. pangea/services/authz.py +4 -0
  35. pangea/services/base.py +5 -1
  36. pangea/services/embargo.py +6 -0
  37. pangea/services/file_scan.py +7 -1
  38. pangea/services/intel.py +4 -0
  39. pangea/services/management.py +720 -0
  40. pangea/services/prompt_guard.py +193 -2
  41. pangea/services/redact.py +477 -7
  42. pangea/services/sanitize.py +5 -1
  43. pangea/services/share/share.py +13 -7
  44. pangea/services/vault/models/asymmetric.py +4 -0
  45. pangea/services/vault/models/common.py +4 -0
  46. pangea/services/vault/models/symmetric.py +4 -0
  47. pangea/services/vault/vault.py +2 -4
  48. pangea/tools.py +13 -9
  49. pangea/utils.py +3 -5
  50. pangea/verify_audit.py +23 -27
  51. {pangea_sdk-6.1.1.dist-info → pangea_sdk-6.2.0b2.dist-info}/METADATA +4 -4
  52. pangea_sdk-6.2.0b2.dist-info/RECORD +62 -0
  53. pangea_sdk-6.1.1.dist-info/RECORD +0 -60
  54. {pangea_sdk-6.1.1.dist-info → pangea_sdk-6.2.0b2.dist-info}/WHEEL +0 -0
@@ -1,13 +1,20 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
5
- from typing import Dict, List, Optional, Union
9
+ from collections.abc import Mapping, Sequence
10
+ from typing import Dict, List, Literal, Optional, Union, cast, overload
11
+
12
+ from pydantic import TypeAdapter
6
13
 
7
14
  import pangea.services.redact as m
8
15
  from pangea.asyncio.services.base import ServiceBaseAsync
9
16
  from pangea.config import PangeaConfig
10
- from pangea.response import PangeaResponse
17
+ from pangea.response import PangeaResponse, PangeaResponseResult
11
18
 
12
19
 
13
20
  class RedactAsync(ServiceBaseAsync):
@@ -64,7 +71,7 @@ class RedactAsync(ServiceBaseAsync):
64
71
  rules: Optional[List[str]] = None,
65
72
  rulesets: Optional[List[str]] = None,
66
73
  return_result: Optional[bool] = None,
67
- redaction_method_overrides: Optional[m.RedactionMethodOverrides] = None,
74
+ redaction_method_overrides: Mapping[str, m.RedactionMethodOverrides] | None = None,
68
75
  llm_request: Optional[bool] = None,
69
76
  vault_parameters: Optional[m.VaultParameters] = None,
70
77
  ) -> PangeaResponse[m.RedactResult]:
@@ -119,7 +126,7 @@ class RedactAsync(ServiceBaseAsync):
119
126
  rules: Optional[List[str]] = None,
120
127
  rulesets: Optional[List[str]] = None,
121
128
  return_result: Optional[bool] = None,
122
- redaction_method_overrides: Optional[m.RedactionMethodOverrides] = None,
129
+ redaction_method_overrides: Mapping[str, m.RedactionMethodOverrides] | None = None,
123
130
  llm_request: bool | None = None,
124
131
  vault_parameters: m.VaultParameters | None = None,
125
132
  ) -> PangeaResponse[m.StructuredResult]:
@@ -200,3 +207,261 @@ class RedactAsync(ServiceBaseAsync):
200
207
  """
201
208
  input = m.UnredactRequest(redacted_data=redacted_data, fpe_context=fpe_context)
202
209
  return await self.request.post("v1/unredact", m.UnredactResult, data=input.model_dump(exclude_none=True))
210
+
211
+ async def get_service_config(self, config_id: str) -> PangeaResponse[m.ServiceConfigResult]:
212
+ """
213
+ Get a service config.
214
+
215
+
216
+ OperationId: redact_post_v1beta_config
217
+ """
218
+ response = await self.request.post("v1beta/config", PangeaResponseResult, data={"id": config_id})
219
+ response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
220
+ return cast(PangeaResponse[m.ServiceConfigResult], response)
221
+
222
+ @overload
223
+ async def create_service_config(
224
+ self,
225
+ name: str,
226
+ *,
227
+ version: Literal["1.0.0"],
228
+ enabled_rules: Sequence[str] | None = None,
229
+ redactions: Mapping[str, m.Redaction] | None = None,
230
+ vault_service_config_id: str | None = None,
231
+ salt_vault_secret_id: str | None = None,
232
+ rules: Mapping[str, m.RuleV1] | None = None,
233
+ rulesets: Mapping[str, m.RulesetV1] | None = None,
234
+ supported_languages: Sequence[Literal["en"]] | None = None,
235
+ ) -> PangeaResponse[m.ServiceConfigResult]:
236
+ """
237
+ Create a v1.0.0 service config.
238
+
239
+ OperationId: redact_post_v1beta_config_create
240
+
241
+ Args:
242
+ vault_service_config_id: Service config used to create the secret
243
+ salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
244
+ """
245
+
246
+ @overload
247
+ async def create_service_config(
248
+ self,
249
+ name: str,
250
+ *,
251
+ version: Literal["2.0.0"] | None = None,
252
+ enabled_rules: Sequence[str] | None = None,
253
+ enforce_enabled_rules: bool | None = None,
254
+ redactions: Mapping[str, m.Redaction] | None = None,
255
+ vault_service_config_id: str | None = None,
256
+ salt_vault_secret_id: str | None = None,
257
+ fpe_vault_secret_id: str | None = None,
258
+ rules: Mapping[str, m.RuleV2] | None = None,
259
+ rulesets: Mapping[str, m.RulesetV2] | None = None,
260
+ supported_languages: Sequence[Literal["en"]] | None = None,
261
+ ) -> PangeaResponse[m.ServiceConfigResult]:
262
+ """
263
+ Create a v2.0.0 service config.
264
+
265
+ OperationId: redact_post_v1beta_config_create
266
+
267
+ Args:
268
+ enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
269
+ vault_service_config_id: Service config used to create the secret
270
+ salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
271
+ fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
272
+ """
273
+
274
+ async def create_service_config(
275
+ self,
276
+ name: str,
277
+ *,
278
+ version: Literal["1.0.0", "2.0.0"] | None = None,
279
+ enabled_rules: Sequence[str] | None = None,
280
+ enforce_enabled_rules: bool | None = None,
281
+ fpe_vault_secret_id: str | None = None,
282
+ redactions: Mapping[str, m.Redaction] | None = None,
283
+ rules: Mapping[str, m.RuleV1 | m.RuleV2] | None = None,
284
+ rulesets: Mapping[str, m.RulesetV1 | m.RulesetV2] | None = None,
285
+ salt_vault_secret_id: str | None = None,
286
+ supported_languages: Sequence[Literal["en"]] | None = None,
287
+ vault_service_config_id: str | None = None,
288
+ ) -> PangeaResponse[m.ServiceConfigResult]:
289
+ """
290
+ Create a service config.
291
+
292
+ OperationId: redact_post_v1beta_config_create
293
+
294
+ Args:
295
+ enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
296
+ fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
297
+ salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
298
+ vault_service_config_id: Service config used to create the secret
299
+ """
300
+
301
+ response = await self.request.post(
302
+ "v1beta/config/create",
303
+ PangeaResponseResult,
304
+ data={
305
+ "name": name,
306
+ "version": version,
307
+ "enabled_rules": enabled_rules,
308
+ "enforce_enabled_rules": enforce_enabled_rules,
309
+ "fpe_vault_secret_id": fpe_vault_secret_id,
310
+ "redactions": redactions,
311
+ "rules": rules,
312
+ "rulesets": rulesets,
313
+ "salt_vault_secret_id": salt_vault_secret_id,
314
+ "supported_languages": supported_languages,
315
+ "vault_service_config_id": vault_service_config_id,
316
+ },
317
+ )
318
+ response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
319
+ return cast(PangeaResponse[m.ServiceConfigResult], response)
320
+
321
+ @overload
322
+ async def update_service_config(
323
+ self,
324
+ config_id: str,
325
+ *,
326
+ version: Literal["1.0.0"],
327
+ name: str,
328
+ updated_at: str,
329
+ enabled_rules: Sequence[str] | None = None,
330
+ redactions: Mapping[str, m.Redaction] | None = None,
331
+ vault_service_config_id: str | None = None,
332
+ salt_vault_secret_id: str | None = None,
333
+ rules: Mapping[str, m.RuleV1] | None = None,
334
+ rulesets: Mapping[str, m.RulesetV1] | None = None,
335
+ supported_languages: Sequence[Literal["en"]] | None = None,
336
+ ) -> PangeaResponse[m.ServiceConfigResult]:
337
+ """
338
+ Update a v1.0.0 service config.
339
+
340
+ OperationId: redact_post_v1beta_config_update
341
+
342
+ Args:
343
+ vault_service_config_id: Service config used to create the secret
344
+ salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
345
+ """
346
+
347
+ @overload
348
+ async def update_service_config(
349
+ self,
350
+ config_id: str,
351
+ *,
352
+ version: Literal["2.0.0"] | None = None,
353
+ name: str,
354
+ updated_at: str,
355
+ enabled_rules: Sequence[str] | None = None,
356
+ enforce_enabled_rules: bool | None = None,
357
+ redactions: Mapping[str, m.Redaction] | None = None,
358
+ vault_service_config_id: str | None = None,
359
+ salt_vault_secret_id: str | None = None,
360
+ fpe_vault_secret_id: str | None = None,
361
+ rules: Mapping[str, m.RuleV2] | None = None,
362
+ rulesets: Mapping[str, m.RulesetV2] | None = None,
363
+ supported_languages: Sequence[Literal["en"]] | None = None,
364
+ ) -> PangeaResponse[m.ServiceConfigResult]:
365
+ """
366
+ Update a v2.0.0 service config.
367
+
368
+ OperationId: redact_post_v1beta_config_update
369
+
370
+ Args:
371
+ enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
372
+ vault_service_config_id: Service config used to create the secret
373
+ salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
374
+ fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
375
+ """
376
+
377
+ async def update_service_config(
378
+ self,
379
+ config_id: str,
380
+ *,
381
+ version: Literal["1.0.0", "2.0.0"] | None = None,
382
+ name: str,
383
+ updated_at: str,
384
+ enabled_rules: Sequence[str] | None = None,
385
+ enforce_enabled_rules: bool | None = None,
386
+ fpe_vault_secret_id: str | None = None,
387
+ redactions: Mapping[str, m.Redaction] | None = None,
388
+ rules: Mapping[str, m.RuleV1 | m.RuleV2] | None = None,
389
+ rulesets: Mapping[str, m.RulesetV1 | m.RulesetV2] | None = None,
390
+ salt_vault_secret_id: str | None = None,
391
+ supported_languages: Sequence[Literal["en"]] | None = None,
392
+ vault_service_config_id: str | None = None,
393
+ ) -> PangeaResponse[m.ServiceConfigResult]:
394
+ """
395
+ Update a service config.
396
+
397
+ OperationId: redact_post_v1beta_config_update
398
+
399
+ Args:
400
+ enforce_enabled_rules: Always run service config enabled rules across all redact calls regardless of flags?
401
+ fpe_vault_secret_id: The ID of the key used by FF3 Encryption algorithms for FPE.
402
+ salt_vault_secret_id: Pangea only allows hashing to be done using a salt value to prevent brute-force attacks.
403
+ vault_service_config_id: Service config used to create the secret
404
+ """
405
+
406
+ response = await self.request.post(
407
+ "v1beta/config/update",
408
+ PangeaResponseResult,
409
+ data={
410
+ "id": config_id,
411
+ "updated_at": updated_at,
412
+ "name": name,
413
+ "version": version,
414
+ "enabled_rules": enabled_rules,
415
+ "enforce_enabled_rules": enforce_enabled_rules,
416
+ "fpe_vault_secret_id": fpe_vault_secret_id,
417
+ "redactions": redactions,
418
+ "rules": rules,
419
+ "rulesets": rulesets,
420
+ "salt_vault_secret_id": salt_vault_secret_id,
421
+ "supported_languages": supported_languages,
422
+ "vault_service_config_id": vault_service_config_id,
423
+ },
424
+ )
425
+ response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
426
+ return cast(PangeaResponse[m.ServiceConfigResult], response)
427
+
428
+ async def delete_service_config(self, config_id: str) -> PangeaResponse[m.ServiceConfigResult]:
429
+ """
430
+ Delete a service config.
431
+
432
+ OperationId: redact_post_v1beta_config_delete
433
+
434
+ Args:
435
+ config_id: An ID for a service config
436
+ """
437
+
438
+ response = await self.request.post("v1beta/config/delete", PangeaResponseResult, data={"id": config_id})
439
+ response.result = TypeAdapter(m.ServiceConfigResult).validate_python(response.json["result"])
440
+ return cast(PangeaResponse[m.ServiceConfigResult], response)
441
+
442
+ async def list_service_configs(
443
+ self,
444
+ *,
445
+ filter: m.ServiceConfigFilter | None = None,
446
+ last: str | None = None,
447
+ order: Literal["asc", "desc"] | None = None,
448
+ order_by: Literal["id", "created_at", "updated_at"] | None = None,
449
+ size: int | None = None,
450
+ ) -> PangeaResponse[m.ServiceConfigListResult]:
451
+ """
452
+ List service configs.
453
+
454
+ OperationId: redact_post_v1beta_config_list
455
+
456
+ Args:
457
+ last: Reflected value from a previous response to obtain the next page of results.
458
+ order: Order results asc(ending) or desc(ending).
459
+ order_by: Which field to order results by.
460
+ size: Maximum results to include in the response.
461
+ """
462
+
463
+ return await self.request.post(
464
+ "v1beta/config/list",
465
+ m.ServiceConfigListResult,
466
+ data={"filter": filter, "last": last, "order": order, "order_by": order_by, "size": size},
467
+ )
@@ -1,5 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
5
9
  import io
@@ -116,7 +120,7 @@ class SanitizeAsync(ServiceBaseAsync):
116
120
  files: Optional[List[Tuple]] = None
117
121
  if file or file_path:
118
122
  if file_path:
119
- file = open(file_path, "rb")
123
+ file = open(file_path, "rb") # noqa: SIM115
120
124
  if transfer_method == TransferMethod.POST_URL and (sha256 is None or crc32c is None or size is None):
121
125
  params = get_file_upload_params(file) # type: ignore[arg-type]
122
126
  crc32c = params.crc_hex if crc32c is None else crc32c
@@ -1,5 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
5
9
  import io
@@ -194,7 +198,7 @@ class ShareAsync(ServiceBaseAsync):
194
198
 
195
199
  async def get_archive(
196
200
  self,
197
- ids: List[str] = [],
201
+ ids: list[str],
198
202
  format: Optional[m.ArchiveFormat] = None,
199
203
  transfer_method: Optional[TransferMethod] = None,
200
204
  bucket_id: Optional[str] = None,
@@ -1,5 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
5
9
  from collections.abc import Mapping
pangea/audit_logger.py CHANGED
@@ -1,5 +1,7 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
4
+
3
5
  import logging
4
6
 
5
7
  import pangea.exceptions as pe
@@ -20,7 +22,7 @@ class AuditLogger(logging.Logger):
20
22
  """
21
23
 
22
24
  def __init__(self, *args, **kwargs):
23
- super(AuditLogger, self).__init__(*args, **kwargs)
25
+ super().__init__(*args, **kwargs)
24
26
 
25
27
  def set_auditor(self, auditor: Audit):
26
28
  """Sets the internal Pangea Audit Service client instance
pangea/deep_verify.py CHANGED
@@ -1,13 +1,16 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
3
 
4
+ from __future__ import annotations
5
+
4
6
  import argparse
5
7
  import io
6
8
  import math
7
9
  import os
8
10
  import sys
11
+ from collections.abc import Iterator
9
12
  from itertools import groupby
10
- from typing import Dict, Iterator, List, Optional, Set, TypedDict, Union
13
+ from typing import Optional, TypedDict, Union
11
14
 
12
15
  import pangea.services.audit.util as audit_util
13
16
  from pangea.services import Audit
@@ -24,7 +27,7 @@ class Errors(TypedDict):
24
27
  buffer_missing: int
25
28
 
26
29
 
27
- root_hashes: Dict[int, str] = {}
30
+ root_hashes: dict[int, str] = {}
28
31
 
29
32
 
30
33
  def num_lines(f: io.TextIOWrapper) -> int:
@@ -124,10 +127,7 @@ def get_root_hash(audit: Audit, tree_size: int) -> str:
124
127
 
125
128
 
126
129
  def print_error(msg: str, level: str = "error"):
127
- if level == "warning":
128
- dot = "🟡"
129
- else:
130
- dot = "🔴"
130
+ dot = "🟡" if level == "warning" else "🔴"
131
131
  print(f"{dot} {msg:200s}")
132
132
 
133
133
 
@@ -148,14 +148,14 @@ def deep_verify(audit: Audit, file: io.TextIOWrapper) -> Errors:
148
148
  }
149
149
 
150
150
  events = file_events(root_hashes, file)
151
- events_by_idx: Union[List[Event], Iterator[Event]]
151
+ events_by_idx: Union[list[Event], Iterator[Event]]
152
152
  cold_indexes = SequenceFollower()
153
153
  for leaf_index, events_by_idx in groupby(events, lambda event: event.get("leaf_index")):
154
154
  events_by_idx = list(events_by_idx)
155
155
  buffer_lines = (cnt, cnt + len(events_by_idx) - 1)
156
156
  if leaf_index is None:
157
157
  print_error(
158
- f"Lines {buffer_lines[0]}-{buffer_lines[1]} ({buffer_lines[1]-buffer_lines[0]+1}): Buffer was not persisted"
158
+ f"Lines {buffer_lines[0]}-{buffer_lines[1]} ({buffer_lines[1] - buffer_lines[0] + 1}): Buffer was not persisted"
159
159
  )
160
160
  errors["not_persisted"] += len(events_by_idx)
161
161
  cnt += len(events_by_idx)
@@ -164,8 +164,8 @@ def deep_verify(audit: Audit, file: io.TextIOWrapper) -> Errors:
164
164
  cold_indexes.add(leaf_index)
165
165
 
166
166
  cold_path_size: Optional[int] = None
167
- hot_indexes: Set[int] = set()
168
- for i, event in enumerate(events_by_idx):
167
+ hot_indexes: set[int] = set()
168
+ for _i, event in enumerate(events_by_idx):
169
169
  cnt += 1
170
170
  tree_size = get_tree_size(event)
171
171
  if tree_size not in root_hashes:
@@ -203,11 +203,11 @@ def deep_verify(audit: Audit, file: io.TextIOWrapper) -> Errors:
203
203
  errors["missing"] += len(hot_indexes_diff)
204
204
  print(f"missing hot indexes: {hot_indexes_diff}")
205
205
  print(f"hot_indexes: {hot_indexes} ")
206
- print(f"events:")
206
+ print("events:")
207
207
  for e in events_by_idx:
208
208
  print(e)
209
209
  print_error(
210
- f"Lines {buffer_lines[0]}-{buffer_lines[1]} ({buffer_lines[1]-buffer_lines[0]}), Buffer #{cold_idx}: {len(hot_indexes_diff)} event(s) missing"
210
+ f"Lines {buffer_lines[0]}-{buffer_lines[1]} ({buffer_lines[1] - buffer_lines[0]}), Buffer #{cold_idx}: {len(hot_indexes_diff)} event(s) missing"
211
211
  )
212
212
 
213
213
  cold_holes = cold_indexes.holes()
@@ -232,7 +232,7 @@ def create_parser():
232
232
  "-f",
233
233
  required=True,
234
234
  type=argparse.FileType("r"),
235
- help="Event input file. Must be a collection of " "JSON Objects separated by newlines",
235
+ help="Event input file. Must be a collection of JSON Objects separated by newlines",
236
236
  )
237
237
  return parser
238
238
 
pangea/deprecated.py CHANGED
@@ -19,7 +19,7 @@ def pangea_deprecated(*args, **kwargs):
19
19
  def wrapper(*iargs, **ikwargs):
20
20
  return deprecated(*args, **kwargs)(f)(*iargs, **ikwargs)
21
21
 
22
- setattr(wrapper, "_deprecated", kwargs)
22
+ wrapper._deprecated = kwargs
23
23
  return wrapper
24
24
 
25
25
  return decorator
pangea/dump_audit.py CHANGED
@@ -7,7 +7,6 @@ import json
7
7
  import os
8
8
  import sys
9
9
  from datetime import datetime
10
- from typing import Tuple
11
10
 
12
11
  import dateutil.parser
13
12
 
@@ -103,7 +102,7 @@ def dump_after(audit: Audit, output: io.TextIOWrapper, start: datetime, last_eve
103
102
 
104
103
  def dump_page(
105
104
  audit: Audit, output: io.TextIOWrapper, start: datetime, end: datetime, first: bool = False
106
- ) -> Tuple[datetime, int, bool, str, int]:
105
+ ) -> tuple[datetime, int, bool, str, int]:
107
106
  PAGE_SIZE = 1000
108
107
  print(start, end)
109
108
  print("Dumping...")
@@ -175,7 +174,7 @@ def parse_args(parser: argparse.ArgumentParser):
175
174
  raise ValueError("domain missing")
176
175
 
177
176
  if args.output is None:
178
- args.output = open(f"dump-{datetime.now().strftime('%Y%m%d%H%M%S')}.jsonl", "w")
177
+ args.output = open(f"dump-{datetime.now().strftime('%Y%m%d%H%M%S')}.jsonl", "w") # noqa: SIM115
179
178
 
180
179
  args.start = make_aware_datetime(args.start)
181
180
  args.end = make_aware_datetime(args.end)
pangea/exceptions.py CHANGED
@@ -1,6 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
3
 
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
4
7
  from typing import List, Optional
5
8
 
6
9
  from pangea.response import AcceptedResult, ErrorField, PangeaResponse
@@ -44,7 +47,7 @@ class PangeaAPIException(PangeaException):
44
47
  response: PangeaResponse
45
48
 
46
49
  def __init__(self, message: str, response: PangeaResponse):
47
- super(PangeaAPIException, self).__init__(message)
50
+ super().__init__(message)
48
51
  self.response = response
49
52
 
50
53
  @property
@@ -92,7 +95,7 @@ class UnauthorizedException(PangeaAPIException):
92
95
 
93
96
  def __init__(self, service_name: str, response: PangeaResponse):
94
97
  message = f"User is not authorized to access service {service_name}"
95
- super(UnauthorizedException, self).__init__(message, response)
98
+ super().__init__(message, response)
96
99
 
97
100
 
98
101
  class NotFound(PangeaAPIException):
@@ -100,20 +103,20 @@ class NotFound(PangeaAPIException):
100
103
 
101
104
  def __init__(self, url: str, response: PangeaResponse):
102
105
  message = f"Resource url:'{url}' not found"
103
- super(NotFound, self).__init__(message, response)
106
+ super().__init__(message, response)
104
107
 
105
108
 
106
109
  class ServiceNotEnabledException(PangeaAPIException):
107
110
  def __init__(self, service_name: str, response: PangeaResponse):
108
111
  message = f"{service_name} is not enabled. Go to console.pangea.cloud/service/{service_name} to enable"
109
- super(ServiceNotEnabledException, self).__init__(message, response)
112
+ super().__init__(message, response)
110
113
 
111
114
 
112
115
  class MissingConfigID(PangeaAPIException):
113
116
  """No config ID was provided in either token scopes or explicitly"""
114
117
 
115
118
  def __init__(self, service_name: str, response: PangeaResponse):
116
- super(MissingConfigID, self).__init__(
119
+ super().__init__(
117
120
  f"Token did not contain a config scope for service {service_name}. Create a new token or provide a config ID explicitly in the service base",
118
121
  response,
119
122
  )
pangea/file_uploader.py CHANGED
@@ -1,5 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  import io
4
8
  import logging
5
9
  from typing import Dict, Optional