pangea-sdk 6.2.0b1__py3-none-any.whl → 6.3.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.
Files changed (55) 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 +70 -169
  5. pangea/asyncio/services/__init__.py +2 -1
  6. pangea/asyncio/services/ai_guard.py +9 -12
  7. pangea/asyncio/services/audit.py +13 -307
  8. pangea/asyncio/services/authn.py +40 -32
  9. pangea/asyncio/services/authz.py +51 -17
  10. pangea/asyncio/services/base.py +4 -0
  11. pangea/asyncio/services/file_scan.py +8 -2
  12. pangea/asyncio/services/intel.py +26 -28
  13. pangea/asyncio/services/redact.py +11 -268
  14. pangea/asyncio/services/sanitize.py +5 -1
  15. pangea/asyncio/services/share.py +5 -1
  16. pangea/asyncio/services/vault.py +71 -55
  17. pangea/audit_logger.py +3 -1
  18. pangea/deep_verify.py +13 -13
  19. pangea/deprecated.py +1 -1
  20. pangea/dump_audit.py +2 -3
  21. pangea/exceptions.py +8 -5
  22. pangea/file_uploader.py +4 -0
  23. pangea/request.py +80 -200
  24. pangea/response.py +21 -18
  25. pangea/services/__init__.py +2 -1
  26. pangea/services/ai_guard.py +35 -24
  27. pangea/services/audit/audit.py +17 -314
  28. pangea/services/audit/models.py +69 -307
  29. pangea/services/audit/signing.py +1 -1
  30. pangea/services/audit/util.py +10 -10
  31. pangea/services/authn/authn.py +39 -31
  32. pangea/services/authn/models.py +183 -148
  33. pangea/services/authz.py +108 -60
  34. pangea/services/base.py +7 -4
  35. pangea/services/embargo.py +6 -0
  36. pangea/services/file_scan.py +8 -2
  37. pangea/services/intel.py +36 -19
  38. pangea/services/redact.py +14 -476
  39. pangea/services/sanitize.py +5 -1
  40. pangea/services/share/share.py +13 -7
  41. pangea/services/vault/models/asymmetric.py +4 -0
  42. pangea/services/vault/models/common.py +15 -12
  43. pangea/services/vault/models/keys.py +4 -9
  44. pangea/services/vault/models/secret.py +3 -8
  45. pangea/services/vault/models/symmetric.py +4 -0
  46. pangea/services/vault/vault.py +69 -59
  47. pangea/tools.py +13 -9
  48. pangea/utils.py +3 -5
  49. pangea/verify_audit.py +23 -27
  50. {pangea_sdk-6.2.0b1.dist-info → pangea_sdk-6.3.0.dist-info}/METADATA +36 -17
  51. pangea_sdk-6.3.0.dist-info/RECORD +60 -0
  52. {pangea_sdk-6.2.0b1.dist-info → pangea_sdk-6.3.0.dist-info}/WHEEL +1 -1
  53. pangea/asyncio/services/management.py +0 -576
  54. pangea/services/management.py +0 -720
  55. pangea_sdk-6.2.0b1.dist-info/RECORD +0 -62
@@ -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 datetime
@@ -7,7 +11,7 @@ import enum
7
11
  from typing import Any, Dict, List, Optional, Sequence, Union
8
12
 
9
13
  from pydantic import Field
10
- from typing_extensions import Annotated, Literal
14
+ from typing_extensions import Annotated
11
15
 
12
16
  from pangea.response import APIRequestModel, APIResponseModel, PangeaDateTime, PangeaResponseResult
13
17
 
@@ -116,20 +120,25 @@ class Event(Dict[str, Any]):
116
120
 
117
121
 
118
122
  class EventEnvelope(APIResponseModel):
119
- """
120
- Contain extra information about an event.
123
+ event: Optional[dict[str, Any]] = None
121
124
 
122
- Arguments:
123
- event -- Event describing auditable activity.
124
- signature -- An optional client-side signature for forgery protection.
125
- public_key -- The base64-encoded ed25519 public key used for the signature, if one is provided
126
- received_at -- A server-supplied timestamp
125
+ signature: Optional[str] = None
126
+ """
127
+ This is the signature of the hash of the canonicalized event that can be
128
+ verified with the public key provided in the public_key field. Signatures
129
+ cannot be used with the redaction feature turned on. If redaction is
130
+ required, the user needs to perform redaction before computing the signature
131
+ that is to be sent with the message. The SDK facilitates this for users.
127
132
  """
128
133
 
129
- event: Dict[str, Any]
130
- signature: Optional[str] = None
131
134
  public_key: Optional[str] = None
132
- received_at: PangeaDateTime
135
+ """
136
+ The base64-encoded ed25519 public key used for the signature, if one is
137
+ provided
138
+ """
139
+
140
+ received_at: Optional[PangeaDateTime] = None
141
+ """A Pangea provided timestamp of when the event was received."""
133
142
 
134
143
 
135
144
  class LogRequest(APIRequestModel):
@@ -180,21 +189,28 @@ class LogBulkRequest(APIRequestModel):
180
189
 
181
190
 
182
191
  class LogResult(PangeaResponseResult):
192
+ envelope: Optional[EventEnvelope] = None
183
193
  """
184
- Result class after an audit log action
185
-
186
- envelope -- Event envelope information.
187
- hash -- Event envelope hash.
188
- unpublished_root -- The current unpublished root.
189
- membership_proof -- A proof for verifying the unpublished root.
190
- consistency_proof -- If prev_root was present in the request, this proof verifies that the new unpublished root is a continuation of the prev_root
194
+ The sealed envelope containing the event that was logged. Includes event
195
+ metadata such as optional client-side signature details and server-added
196
+ timestamps.
191
197
  """
192
198
 
193
- envelope: Optional[EventEnvelope] = None
194
- hash: str
199
+ hash: Annotated[Optional[str], Field(max_length=64, min_length=64)] = None
200
+ """The hash of the event data."""
201
+
195
202
  unpublished_root: Optional[str] = None
203
+ """The current unpublished root."""
204
+
196
205
  membership_proof: Optional[str] = None
206
+ """A proof for verifying that the buffer_root contains the received event"""
207
+
197
208
  consistency_proof: Optional[List[str]] = None
209
+ """
210
+ If prev_buffer_root was present in the request, this proof verifies that the
211
+ new unpublished root is a continuation of prev_unpublished_root
212
+ """
213
+
198
214
  consistency_verification: EventVerification = EventVerification.NONE
199
215
  membership_verification: EventVerification = EventVerification.NONE
200
216
  signature_verification: EventVerification = EventVerification.NONE
@@ -357,29 +373,47 @@ class RootResult(PangeaResponseResult):
357
373
 
358
374
 
359
375
  class SearchEvent(APIResponseModel):
376
+ envelope: EventEnvelope
377
+
378
+ membership_proof: Optional[str] = None
379
+ """A cryptographic proof that the record has been persisted in the log"""
380
+
381
+ hash: Annotated[Optional[str], Field(max_length=64, min_length=64)] = None
382
+ """The record's hash"""
383
+
384
+ published: Optional[bool] = None
385
+ """
386
+ If true, a root has been published after this event. If false, there is no
387
+ published root for this event
360
388
  """
361
- Event information received after a search request
362
389
 
363
- Arguments:
364
- envelope -- Event related information.
365
- hash -- The record's hash.
366
- leaf_index -- The index of the leaf of the Merkle Tree where this record was inserted.
367
- membership_proof -- A cryptographic proof that the record has been persisted in the log.
368
- consistency_verification -- Consistency verification calculated if required.
369
- membership_verification -- Membership verification calculated if required.
370
- signature_verification -- Signature verification calculated if required.
371
- fpe_context -- The context data needed to decrypt secure audit events that have been redacted with format preserving encryption.
390
+ imported: Optional[bool] = None
391
+ """
392
+ If true, the even was imported manually and not logged by the standard
393
+ procedure. Some features such as tamper proofing may not be available
372
394
  """
373
395
 
374
- envelope: EventEnvelope
375
- hash: str
376
- membership_proof: Optional[str] = None
377
- published: Optional[bool] = None
378
396
  leaf_index: Optional[int] = None
397
+ """
398
+ The index of the leaf of the Merkle Tree where this record was inserted or
399
+ null if published=false
400
+ """
401
+
402
+ valid_signature: Optional[bool] = None
403
+ """
404
+ Result of the verification of the Vault signature, if the event was signed
405
+ and the parameter `verify_signature` is `true`
406
+ """
407
+
408
+ fpe_context: Optional[str] = None
409
+ """
410
+ The context data needed to decrypt secure audit events that have been
411
+ redacted with format preserving encryption.
412
+ """
413
+
379
414
  consistency_verification: EventVerification = EventVerification.NONE
380
415
  membership_verification: EventVerification = EventVerification.NONE
381
416
  signature_verification: EventVerification = EventVerification.NONE
382
- fpe_context: Optional[str] = None
383
417
 
384
418
 
385
419
  class SearchResultOutput(PangeaResponseResult):
@@ -498,275 +532,3 @@ class ExportRequest(APIRequestModel):
498
532
  Whether or not to include the root hash of the tree and the membership proof
499
533
  for each record.
500
534
  """
501
-
502
-
503
- class AuditSchemaField(APIResponseModel):
504
- """A description of a field in an audit log."""
505
-
506
- id: str
507
- """Prefix name / identity for the field."""
508
-
509
- type: Literal["boolean", "datetime", "integer", "string", "string-unindexed", "text"]
510
- """The data type for the field."""
511
-
512
- description: Optional[str] = None
513
- """Human display description of the field."""
514
-
515
- name: Optional[str] = None
516
- """Human display name/title of the field."""
517
-
518
- redact: Optional[bool] = None
519
- """If true, redaction is performed against this field (if configured.) Only valid for string type."""
520
-
521
- required: Optional[bool] = None
522
- """If true, this field is required to exist in all logged events."""
523
-
524
- size: Optional[int] = None
525
- """The maximum size of the field. Only valid for strings, which limits number of UTF-8 characters."""
526
-
527
- ui_default_visible: Optional[bool] = None
528
- """If true, this field is visible by default in audit UIs."""
529
-
530
-
531
- class AuditSchema(APIResponseModel):
532
- """A description of acceptable fields for an audit log."""
533
-
534
- client_signable: Optional[bool] = None
535
- """If true, records contain fields to support client/vault signing."""
536
-
537
- save_malformed: Optional[str] = None
538
- """Save (or reject) malformed AuditEvents."""
539
-
540
- tamper_proofing: Optional[bool] = None
541
- """If true, records contain fields to support tamper-proofing."""
542
-
543
- fields: Optional[List[AuditSchemaField]] = None
544
- """List of field definitions."""
545
-
546
-
547
- class ForwardingConfiguration(APIResponseModel):
548
- """Configuration for forwarding audit logs to external systems."""
549
-
550
- type: str
551
- """Type of forwarding configuration."""
552
-
553
- forwarding_enabled: Optional[bool] = False
554
- """Whether forwarding is enabled."""
555
-
556
- event_url: Optional[str] = None
557
- """URL where events will be written to. Must use HTTPS."""
558
-
559
- ack_url: Optional[str] = None
560
- """If indexer acknowledgement is required, this must be provided along with a 'channel_id'."""
561
-
562
- channel_id: Optional[str] = None
563
- """An optional splunk channel included in each request if indexer acknowledgement is required."""
564
-
565
- public_cert: Optional[str] = None
566
- """Public certificate if a self signed TLS cert is being used."""
567
-
568
- index: Optional[str] = None
569
- """Optional splunk index passed in the record bodies."""
570
-
571
- vault_config_id: Optional[str] = None
572
- """The vault config used to store the HEC token."""
573
-
574
- vault_secret_id: Optional[str] = None
575
- """The secret ID where the HEC token is stored in vault."""
576
-
577
-
578
- class ServiceConfigV1(PangeaResponseResult):
579
- """Configuration options available for audit service"""
580
-
581
- id: Optional[str] = None
582
- """The config ID"""
583
-
584
- version: Literal[1] = 1
585
-
586
- created_at: Optional[str] = None
587
- """The DB timestamp when this config was created. Ignored when submitted."""
588
-
589
- updated_at: Optional[str] = None
590
- """The DB timestamp when this config was last updated at"""
591
-
592
- name: Optional[str] = None
593
- """Configuration name"""
594
-
595
- retention: Optional[str] = None
596
- """Retention window to store audit logs."""
597
-
598
- cold_query_result_retention: Optional[str] = None
599
- """Retention window for cold query result / state information."""
600
-
601
- hot_storage: Optional[str] = None
602
- """Retention window to keep audit logs in hot storage."""
603
-
604
- query_result_retention: Optional[str] = None
605
- """Length of time to preserve server-side query result caching."""
606
-
607
- redact_service_config_id: Optional[str] = None
608
- """A redact service config that will be used to redact PII from logs."""
609
-
610
- redaction_fields: Optional[List[str]] = None
611
- """Fields to perform redaction against."""
612
-
613
- vault_service_config_id: Optional[str] = None
614
- """A vault service config that will be used to sign logs."""
615
-
616
- vault_key_id: Optional[str] = None
617
- """ID of the Vault key used for signing. If missing, use a default Audit key"""
618
-
619
- vault_sign: Optional[bool] = None
620
- """Enable/disable event signing"""
621
-
622
-
623
- class ServiceConfigV2(PangeaResponseResult):
624
- """Configuration options available for audit service"""
625
-
626
- audit_schema: AuditSchema = Field(alias="schema")
627
- """Audit log field configuration. Only settable at create time."""
628
-
629
- version: Literal[2] = 2
630
-
631
- cold_query_result_retention: Optional[str] = None
632
- """Retention window for cold query result / state information."""
633
-
634
- created_at: Optional[str] = None
635
- """The DB timestamp when this config was created. Ignored when submitted."""
636
-
637
- hot_storage: Optional[str] = None
638
- """Retention window to keep audit logs in hot storage."""
639
-
640
- id: Optional[str] = None
641
- """The config ID"""
642
-
643
- name: Optional[str] = None
644
- """Configuration name"""
645
-
646
- query_result_retention: Optional[str] = None
647
- """Length of time to preserve server-side query result caching."""
648
-
649
- redact_service_config_id: Optional[str] = None
650
- """A redact service config that will be used to redact PII from logs."""
651
-
652
- retention: Optional[str] = None
653
- """Retention window to store audit logs."""
654
-
655
- updated_at: Optional[str] = None
656
- """The DB timestamp when this config was last updated at"""
657
-
658
- vault_key_id: Optional[str] = None
659
- """ID of the Vault key used for signing. If missing, use a default Audit key"""
660
-
661
- vault_service_config_id: Optional[str] = None
662
- """A vault service config that will be used to sign logs."""
663
-
664
- vault_sign: Optional[bool] = None
665
- """Enable/disable event signing"""
666
-
667
- forwarding_configuration: Optional[ForwardingConfiguration] = None
668
- """Configuration for forwarding audit logs to external systems."""
669
-
670
-
671
- class ServiceConfigV3(PangeaResponseResult):
672
- """Configuration options available for audit service"""
673
-
674
- audit_schema: AuditSchema = Field(alias="schema")
675
- """Audit log field configuration. Only settable at create time."""
676
-
677
- version: Literal[3] = 3
678
- """Version of the service config."""
679
-
680
- cold_storage: Optional[str] = None
681
- """Retention window for logs in cold storage. Deleted afterwards."""
682
-
683
- created_at: Optional[str] = None
684
- """The DB timestamp when this config was created. Ignored when submitted."""
685
-
686
- forwarding_configuration: Optional[ForwardingConfiguration] = None
687
- """Configuration for forwarding audit logs to external systems."""
688
-
689
- hot_storage: Optional[str] = None
690
- """Retention window for logs in hot storage. Migrated to warm, cold, or deleted afterwards."""
691
-
692
- id: Optional[str] = None
693
- """The config ID"""
694
-
695
- name: Optional[str] = None
696
- """Configuration name"""
697
-
698
- redact_service_config_id: Optional[str] = None
699
- """A redact service config that will be used to redact PII from logs."""
700
-
701
- updated_at: Optional[str] = None
702
- """The DB timestamp when this config was last updated at"""
703
-
704
- vault_key_id: Optional[str] = None
705
- """ID of the Vault key used for signing. If missing, use a default Audit key"""
706
-
707
- vault_service_config_id: Optional[str] = None
708
- """A vault service config that will be used to sign logs."""
709
-
710
- vault_sign: Optional[bool] = None
711
- """Enable/disable event signing"""
712
-
713
- warm_storage: Optional[str] = None
714
- """Retention window for logs in warm storage. Migrated to cold or deleted afterwards."""
715
-
716
-
717
- ServiceConfig = Annotated[
718
- Union[ServiceConfigV1, ServiceConfigV2, ServiceConfigV3],
719
- Field(discriminator="version"),
720
- ]
721
- """Configuration options available for audit service"""
722
-
723
-
724
- class ServiceConfigFilter(APIRequestModel):
725
- id: Optional[str] = None
726
- """Only records where id equals this value."""
727
-
728
- id__contains: Optional[Sequence[str]] = None
729
- """Only records where id includes each substring."""
730
-
731
- id__in: Optional[Sequence[str]] = None
732
- """Only records where id equals one of the provided substrings."""
733
-
734
- created_at: Optional[str] = None
735
- """Only records where created_at equals this value."""
736
-
737
- created_at__gt: Optional[str] = None
738
- """Only records where created_at is greater than this value."""
739
-
740
- created_at__gte: Optional[str] = None
741
- """Only records where created_at is greater than or equal to this value."""
742
-
743
- created_at__lt: Optional[str] = None
744
- """Only records where created_at is less than this value."""
745
-
746
- created_at__lte: Optional[str] = None
747
- """Only records where created_at is less than or equal to this value."""
748
-
749
- updated_at: Optional[str] = None
750
- """Only records where updated_at equals this value."""
751
-
752
- updated_at__gt: Optional[str] = None
753
- """Only records where updated_at is greater than this value."""
754
-
755
- updated_at__gte: Optional[str] = None
756
- """Only records where updated_at is greater than or equal to this value."""
757
-
758
- updated_at__lt: Optional[str] = None
759
- """Only records where updated_at is less than this value."""
760
-
761
- updated_at__lte: Optional[str] = None
762
- """Only records where updated_at is less than or equal to this value."""
763
-
764
-
765
- class ServiceConfigListResult(PangeaResponseResult):
766
- count: int
767
- """The total number of service configs matched by the list request."""
768
-
769
- last: str
770
- """Used to fetch the next page of the current listing when provided in a repeated request's last parameter."""
771
-
772
- items: Sequence[ServiceConfig]
@@ -81,7 +81,7 @@ class Signer:
81
81
  with open(self.private_key_file, "rb") as file:
82
82
  file_bytes = file.read()
83
83
  except FileNotFoundError:
84
- raise Exception(f"Error: Failed opening private key file {self.private_key_file}")
84
+ raise Exception(f"Error: Failed opening private key file {self.private_key_file}") from None
85
85
 
86
86
  privkey = self._decode_private_key(file_bytes)
87
87
  for cls, signer in signers.items():
@@ -1,5 +1,11 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
7
+ from __future__ import annotations
8
+
3
9
  import base64
4
10
  import json
5
11
  import logging
@@ -155,9 +161,9 @@ def verify_membership_proof(node_hash: Hash, root_hash: Hash, proof: MembershipP
155
161
  def normalize_log(data: dict) -> dict:
156
162
  ans = {}
157
163
  for key in data:
158
- if type(data[key]) == datetime:
164
+ if isinstance(data[key], datetime):
159
165
  ans[key] = format_datetime(data[key])
160
- elif type(data[key]) == dict:
166
+ elif isinstance(data[key], dict):
161
167
  ans[key] = normalize_log(data[key]) # type: ignore[assignment]
162
168
  else:
163
169
  ans[key] = data[key]
@@ -223,9 +229,7 @@ def get_arweave_published_roots(tree_name: str, tree_sizes: Collection[int]) ->
223
229
  }
224
230
  }
225
231
  }
226
- """.replace(
227
- "{tree_sizes}", ", ".join(f'"{tree_size}"' for tree_size in tree_sizes)
228
- ).replace(
232
+ """.replace("{tree_sizes}", ", ".join(f'"{tree_size}"' for tree_size in tree_sizes)).replace(
229
233
  "{tree_name}", tree_name
230
234
  )
231
235
 
@@ -273,8 +277,4 @@ def verify_consistency_proof(new_root: Hash, prev_root: Hash, proof: Consistency
273
277
  return False
274
278
 
275
279
  logger.debug("Verifying the proofs for the new root")
276
- for item in proof:
277
- if not verify_membership_proof(item.node_hash, new_root, item.proof):
278
- return False
279
-
280
- return True
280
+ return all(verify_membership_proof(item.node_hash, new_root, item.proof) for item in proof)