pangea-sdk 3.1.0__tar.gz → 3.2.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/PKG-INFO +1 -1
  2. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/__init__.py +1 -1
  3. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/audit.py +82 -3
  4. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/exceptions.py +1 -1
  5. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/response.py +6 -3
  6. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/audit.py +163 -62
  7. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/models.py +32 -0
  8. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pyproject.toml +1 -1
  9. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/README.md +0 -0
  10. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/request.py +0 -0
  11. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/__init__.py +0 -0
  12. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/authn.py +0 -0
  13. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/base.py +0 -0
  14. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/embargo.py +0 -0
  15. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/file_scan.py +0 -0
  16. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/intel.py +0 -0
  17. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/redact.py +0 -0
  18. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/vault.py +0 -0
  19. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/audit_logger.py +0 -0
  20. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/config.py +0 -0
  21. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/deep_verify.py +0 -0
  22. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/deprecated.py +0 -0
  23. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/dump_audit.py +0 -0
  24. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/request.py +0 -0
  25. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/__init__.py +0 -0
  26. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/exceptions.py +0 -0
  27. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/signing.py +0 -0
  28. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/util.py +0 -0
  29. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/authn/authn.py +0 -0
  30. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/authn/models.py +0 -0
  31. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/base.py +0 -0
  32. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/embargo.py +0 -0
  33. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/file_scan.py +0 -0
  34. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/intel.py +0 -0
  35. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/redact.py +0 -0
  36. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/asymmetric.py +0 -0
  37. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/common.py +0 -0
  38. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/secret.py +0 -0
  39. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/symmetric.py +0 -0
  40. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/vault.py +0 -0
  41. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/tools.py +0 -0
  42. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/utils.py +0 -0
  43. {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/verify_audit.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pangea-sdk
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Summary: Pangea API SDK
5
5
  License: MIT
6
6
  Keywords: Pangea,SDK,Audit
@@ -1,4 +1,4 @@
1
- __version__ = "3.1.0"
1
+ __version__ = "3.2.0"
2
2
 
3
3
  from pangea.asyncio.request import PangeaRequestAsync
4
4
  from pangea.config import PangeaConfig
@@ -1,13 +1,15 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
3
  import datetime
4
- from typing import Any, Dict, Optional, Union
4
+ from typing import Any, Dict, List, Optional, Union
5
5
 
6
+ import pangea.exceptions as pexc
6
7
  from pangea.response import PangeaResponse
7
8
  from pangea.services.audit.audit import AuditBase
8
9
  from pangea.services.audit.exceptions import AuditException
9
10
  from pangea.services.audit.models import (
10
11
  Event,
12
+ LogBulkResult,
11
13
  LogResult,
12
14
  RootRequest,
13
15
  RootResult,
@@ -172,9 +174,86 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
172
174
  print(f"\\t{err.detail} \\n")
173
175
  """
174
176
 
175
- input = self._pre_log_process(event, sign_local=sign_local, verify=verify, verbose=verbose)
177
+ input = self._get_log_request(event, sign_local=sign_local, verify=verify, verbose=verbose)
176
178
  response = await self.request.post("v1/log", LogResult, data=input.dict(exclude_none=True))
177
- return self.handle_log_response(response, verify=verify)
179
+ if response.success:
180
+ self._process_log_result(response.result, verify=verify)
181
+ return response
182
+
183
+ async def log_bulk(
184
+ self,
185
+ events: List[Dict[str, Any]],
186
+ sign_local: bool = False,
187
+ verbose: Optional[bool] = None,
188
+ ) -> PangeaResponse[LogBulkResult]:
189
+ """
190
+ Log an entry
191
+
192
+ Create a log entry in the Secure Audit Log.
193
+ Args:
194
+ events (List[dict[str, Any]]): events to be logged
195
+ verify (bool, optional): True to verify logs consistency after response.
196
+ sign_local (bool, optional): True to sign event with local key.
197
+ verbose (bool, optional): True to get a more verbose response.
198
+ Raises:
199
+ AuditException: If an audit based api exception happens
200
+ PangeaAPIException: If an API Error happens
201
+
202
+ Returns:
203
+ A PangeaResponse where the hash of event data and optional verbose
204
+ results are returned in the response.result field.
205
+ Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#log-an-entry).
206
+
207
+ Examples:
208
+ FIXME:
209
+ """
210
+
211
+ input = self._get_log_request(events, sign_local=sign_local, verify=False, verbose=verbose)
212
+ response = await self.request.post("v2/log", LogBulkResult, data=input.dict(exclude_none=True))
213
+ if response.success:
214
+ for result in response.result.results:
215
+ self._process_log_result(result, verify=True)
216
+ return response
217
+
218
+ async def log_bulk_async(
219
+ self,
220
+ events: List[Dict[str, Any]],
221
+ sign_local: bool = False,
222
+ verbose: Optional[bool] = None,
223
+ ) -> PangeaResponse[LogBulkResult]:
224
+ """
225
+ Log an entry
226
+
227
+ Create a log entry in the Secure Audit Log.
228
+ Args:
229
+ events (List[dict[str, Any]]): events to be logged
230
+ verify (bool, optional): True to verify logs consistency after response.
231
+ sign_local (bool, optional): True to sign event with local key.
232
+ verbose (bool, optional): True to get a more verbose response.
233
+ Raises:
234
+ AuditException: If an audit based api exception happens
235
+ PangeaAPIException: If an API Error happens
236
+
237
+ Returns:
238
+ A PangeaResponse where the hash of event data and optional verbose
239
+ results are returned in the response.result field.
240
+ Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#log-an-entry).
241
+
242
+ Examples:
243
+ FIXME:
244
+ """
245
+
246
+ input = self._get_log_request(events, sign_local=sign_local, verify=False, verbose=verbose)
247
+ try:
248
+ response = await self.request.post(
249
+ "v2/log_async", LogBulkResult, data=input.dict(exclude_none=True), poll_result=False
250
+ )
251
+ except pexc.AcceptedRequestException as e:
252
+ return e.response
253
+ if response.success:
254
+ for result in response.result.results:
255
+ self._process_log_result(result, verify=True)
256
+ return response
178
257
 
179
258
  async def search(
180
259
  self,
@@ -119,7 +119,7 @@ class AcceptedRequestException(PangeaAPIException):
119
119
  """Accepted request exception. Async response"""
120
120
 
121
121
  request_id: str
122
- accepted_result: Optional[AcceptedResult]
122
+ accepted_result: Optional[AcceptedResult] = None
123
123
 
124
124
  def __init__(self, response: PangeaResponse):
125
125
  message = f"summary: {response.summary}. request_id: {response.request_id}."
@@ -76,7 +76,7 @@ class AcceptedStatus(APIResponseModel):
76
76
 
77
77
 
78
78
  class AcceptedResult(PangeaResponseResult):
79
- accepted_status: AcceptedStatus
79
+ accepted_status: Optional[AcceptedStatus] = None
80
80
 
81
81
 
82
82
  class PangeaError(PangeaResponseResult):
@@ -144,8 +144,11 @@ class PangeaResponse(Generic[T], ResponseHeader):
144
144
  if self.raw_result is not None and issubclass(self.result_class, PangeaResponseResult) and self.success
145
145
  else None
146
146
  )
147
- if not self.success and self.http_status != 202:
148
- self.pangea_error = PangeaError(**self.raw_result) if self.raw_result is not None else None
147
+ if not self.success:
148
+ if self.http_status == 202:
149
+ self.accepted_result = AcceptedResult(**self.raw_result) if self.raw_result is not None else None
150
+ else:
151
+ self.pangea_error = PangeaError(**self.raw_result) if self.raw_result is not None else None
149
152
 
150
153
  @property
151
154
  def success(self) -> bool:
@@ -2,14 +2,18 @@
2
2
  # Author: Pangea Cyber Corporation
3
3
  import datetime
4
4
  import json
5
- from typing import Any, Dict, Optional, Union
5
+ from typing import Any, Dict, List, Optional, Union
6
6
 
7
+ import pangea.exceptions as pexc
7
8
  from pangea.response import PangeaResponse
8
9
  from pangea.services.audit.exceptions import AuditException, EventCorruption
9
10
  from pangea.services.audit.models import (
10
11
  Event,
11
12
  EventEnvelope,
12
13
  EventVerification,
14
+ LogBulkRequest,
15
+ LogBulkResult,
16
+ LogEvent,
13
17
  LogRequest,
14
18
  LogResult,
15
19
  PublishedRoot,
@@ -56,7 +60,29 @@ class AuditBase:
56
60
  self.prev_unpublished_root_hash: Optional[str] = None
57
61
  self.tenant_id = tenant_id
58
62
 
59
- def _pre_log_process(self, event: dict, sign_local: bool, verify: bool, verbose: bool) -> LogRequest:
63
+ def _get_log_request(
64
+ self, events: Union[dict, List[dict]], sign_local: bool, verify: bool, verbose: Optional[bool]
65
+ ) -> Union[LogRequest, LogBulkResult]:
66
+ if isinstance(events, list):
67
+ request_events: List[LogEvent] = []
68
+ for e in events:
69
+ request_events.append(self._process_log(e, sign_local=sign_local))
70
+
71
+ input = LogBulkRequest(events=request_events, verbose=verbose)
72
+
73
+ elif isinstance(events, dict):
74
+ log = self._process_log(events, sign_local=sign_local)
75
+ input = LogRequest(event=log.event, signature=log.signature, public_key=log.public_key)
76
+ input.verbose = True if verify else verbose
77
+ if verify and self.prev_unpublished_root_hash:
78
+ input.prev_root = self.prev_unpublished_root_hash
79
+
80
+ else:
81
+ raise AttributeError(f"events should be a dict or a list[dict] and it is {type(events)}")
82
+
83
+ return input
84
+
85
+ def _process_log(self, event: dict, sign_local: bool) -> LogEvent:
60
86
  if event.get("tenant_id", None) is None and self.tenant_id:
61
87
  event["tenant_id"] = self.tenant_id
62
88
 
@@ -66,70 +92,60 @@ class AuditBase:
66
92
  if sign_local is True and self.signer is None:
67
93
  raise AuditException("Error: the `signing` parameter set, but `signer` is not configured")
68
94
 
69
- input = LogRequest(event=event, verbose=verbose)
70
-
95
+ signature = None
96
+ pki = None
71
97
  if sign_local is True:
72
98
  data2sign = canonicalize_event(event)
73
99
  signature = self.signer.sign(data2sign)
74
- if signature is not None:
75
- input.signature = signature
76
- else:
100
+ if signature is None:
77
101
  raise AuditException("Error: failure signing message")
78
102
 
79
103
  # Add public key value to public key info and serialize
80
- self._set_public_key(input, self.signer, self.public_key_info)
81
-
82
- if verify:
83
- input.verbose = True
84
- if self.prev_unpublished_root_hash:
85
- input.prev_root = self.prev_unpublished_root_hash
86
-
87
- return input
104
+ pki = self._get_public_key_info(self.signer, self.public_key_info)
88
105
 
89
- def handle_log_response(self, response: PangeaResponse, verify: bool) -> PangeaResponse[LogResult]:
90
- if not response.success:
91
- return response
106
+ return LogEvent(event=event, signature=signature, public_key=pki)
92
107
 
93
- new_unpublished_root_hash = response.result.unpublished_root
108
+ def _process_log_result(self, result: LogResult, verify: bool):
109
+ new_unpublished_root_hash = result.unpublished_root
94
110
 
95
111
  if verify:
96
- if response.result.envelope:
112
+ if result.envelope:
97
113
  # verify event hash
98
- if response.result.hash and not verify_envelope_hash(response.result.envelope, response.result.hash):
114
+ if result.hash and not verify_envelope_hash(result.envelope, result.hash):
99
115
  # it's a extreme case, it's OK to raise an exception
100
- raise EventCorruption("Error: Event hash failed.", response.result.envelope)
116
+ raise EventCorruption("Error: Event hash failed.", result.envelope)
101
117
 
102
- response.result.signature_verification = self.verify_signature(response.result.envelope)
118
+ result.signature_verification = self.verify_signature(result.envelope)
103
119
 
104
120
  if new_unpublished_root_hash:
105
- if response.result.membership_proof is not None:
121
+ if result.membership_proof is not None:
106
122
  # verify membership proofs
107
- membership_proof = decode_membership_proof(response.result.membership_proof)
123
+ membership_proof = decode_membership_proof(result.membership_proof)
108
124
  if verify_membership_proof(
109
- node_hash=decode_hash(response.result.hash),
125
+ node_hash=decode_hash(result.hash),
110
126
  root_hash=decode_hash(new_unpublished_root_hash),
111
127
  proof=membership_proof,
112
128
  ):
113
- response.result.membership_verification = EventVerification.PASS
129
+ result.membership_verification = EventVerification.PASS
114
130
  else:
115
- response.result.membership_verification = EventVerification.FAIL
131
+ result.membership_verification = EventVerification.FAIL
116
132
 
117
133
  # verify consistency proofs (following events)
118
- if response.result.consistency_proof is not None and self.prev_unpublished_root_hash:
119
- consistency_proof = decode_consistency_proof(response.result.consistency_proof)
134
+ if result.consistency_proof is not None and self.prev_unpublished_root_hash:
135
+ consistency_proof = decode_consistency_proof(result.consistency_proof)
120
136
  if verify_consistency_proof(
121
137
  new_root=decode_hash(new_unpublished_root_hash),
122
138
  prev_root=decode_hash(self.prev_unpublished_root_hash),
123
139
  proof=consistency_proof,
124
140
  ):
125
- response.result.consistency_verification = EventVerification.PASS
141
+ result.consistency_verification = EventVerification.PASS
126
142
  else:
127
- response.result.consistency_verification = EventVerification.FAIL
143
+ result.consistency_verification = EventVerification.FAIL
128
144
 
129
145
  # Update prev unpublished root
130
146
  if new_unpublished_root_hash:
131
147
  self.prev_unpublished_root_hash = new_unpublished_root_hash
132
- return response
148
+ return
133
149
 
134
150
  def handle_results_response(
135
151
  self, response: PangeaResponse[SearchResultOutput], verify_consistency: bool = False, verify_events: bool = True
@@ -348,12 +364,10 @@ class AuditBase:
348
364
  else:
349
365
  return EventVerification.NONE
350
366
 
351
- def _set_public_key(self, input: LogRequest, signer: Signer, public_key_info: Dict[str, str]):
367
+ def _get_public_key_info(self, signer: Signer, public_key_info: Dict[str, str]):
352
368
  public_key_info["key"] = signer.get_public_key_PEM()
353
369
  public_key_info["algorithm"] = signer.get_algorithm()
354
- input.public_key = json.dumps(
355
- public_key_info, ensure_ascii=False, allow_nan=False, separators=(",", ":"), sort_keys=True
356
- )
370
+ return json.dumps(public_key_info, ensure_ascii=False, allow_nan=False, separators=(",", ":"), sort_keys=True)
357
371
 
358
372
 
359
373
  class Audit(ServiceBase, AuditBase):
@@ -444,16 +458,13 @@ class Audit(ServiceBase, AuditBase):
444
458
  A PangeaResponse where the hash of event data and optional verbose
445
459
  results are returned in the response.result field.
446
460
  Available response fields can be found in our
447
- [API documentation](https://pangea.cloud/docs/api/audit#log-an-entry).
461
+ [API documentation](https://pangea.cloud/docs/api/audit#/v1/log).
448
462
 
449
463
  Examples:
450
- try:
451
- log_response = audit.log(message="Hello world", verbose=False)
452
- print(f"Response. Hash: {log_response.result.hash}")
453
- except pe.PangeaAPIException as e:
454
- print(f"Request Error: {e.response.summary}")
455
- for err in e.errors:
456
- print(f"\\t{err.detail} \\n")
464
+ log_response = audit.log(
465
+ message="hello world",
466
+ verbose=True,
467
+ )
457
468
  """
458
469
 
459
470
  event = Event(
@@ -481,6 +492,7 @@ class Audit(ServiceBase, AuditBase):
481
492
  Log an entry
482
493
 
483
494
  Create a log entry in the Secure Audit Log.
495
+
484
496
  Args:
485
497
  event (dict[str, Any]): event to be logged
486
498
  verify (bool, optional): True to verify logs consistency after response.
@@ -493,11 +505,11 @@ class Audit(ServiceBase, AuditBase):
493
505
  Returns:
494
506
  A PangeaResponse where the hash of event data and optional verbose
495
507
  results are returned in the response.result field.
496
- Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#log-an-entry).
508
+ Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v1/log).
497
509
 
498
510
  Examples:
499
511
  try:
500
- log_response = audit.log({"message"="Hello world"}, verbose=False)
512
+ log_response = audit.log({"message": "hello world"}, verbose=True)
501
513
  print(f"Response. Hash: {log_response.result.hash}")
502
514
  except pe.PangeaAPIException as e:
503
515
  print(f"Request Error: {e.response.summary}")
@@ -505,9 +517,98 @@ class Audit(ServiceBase, AuditBase):
505
517
  print(f"\\t{err.detail} \\n")
506
518
  """
507
519
 
508
- input = self._pre_log_process(event, sign_local=sign_local, verify=verify, verbose=verbose)
520
+ input = self._get_log_request(event, sign_local=sign_local, verify=verify, verbose=verbose)
509
521
  response = self.request.post("v1/log", LogResult, data=input.dict(exclude_none=True))
510
- return self.handle_log_response(response, verify=verify)
522
+ if response.success:
523
+ self._process_log_result(response.result, verify=verify)
524
+ return response
525
+
526
+ def log_bulk(
527
+ self,
528
+ events: List[Dict[str, Any]],
529
+ sign_local: bool = False,
530
+ verbose: Optional[bool] = None,
531
+ ) -> PangeaResponse[LogBulkResult]:
532
+ """
533
+ Log multiple entries
534
+
535
+ Create multiple log entries in the Secure Audit Log.
536
+
537
+ OperationId: audit_post_v2_log
538
+
539
+ Args:
540
+ events (List[dict[str, Any]]): events to be logged
541
+ sign_local (bool, optional): True to sign event with local key.
542
+ verbose (bool, optional): True to get a more verbose response.
543
+ Raises:
544
+ AuditException: If an audit based api exception happens
545
+ PangeaAPIException: If an API Error happens
546
+
547
+ Returns:
548
+ A PangeaResponse where the hash of event data and optional verbose
549
+ results are returned in the response.result field.
550
+ Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v2/log).
551
+
552
+ Examples:
553
+ log_response = audit.log_bulk(
554
+ events=[{"message": "hello world"}],
555
+ verbose=True,
556
+ )
557
+ """
558
+
559
+ input = self._get_log_request(events, sign_local=sign_local, verify=False, verbose=verbose)
560
+ response = self.request.post("v2/log", LogBulkResult, data=input.dict(exclude_none=True))
561
+
562
+ if response.success:
563
+ for result in response.result.results:
564
+ self._process_log_result(result, verify=True)
565
+ return response
566
+
567
+ def log_bulk_async(
568
+ self,
569
+ events: List[Dict[str, Any]],
570
+ sign_local: bool = False,
571
+ verbose: Optional[bool] = None,
572
+ ) -> PangeaResponse[LogBulkResult]:
573
+ """
574
+ Log multiple entries asynchronously
575
+
576
+ Asynchronously create multiple log entries in the Secure Audit Log.
577
+
578
+ Args:
579
+ events (List[dict[str, Any]]): events to be logged
580
+ sign_local (bool, optional): True to sign event with local key.
581
+ verbose (bool, optional): True to get a more verbose response.
582
+ Raises:
583
+ AuditException: If an audit based api exception happens
584
+ PangeaAPIException: If an API Error happens
585
+
586
+ Returns:
587
+ A PangeaResponse where the hash of event data and optional verbose
588
+ results are returned in the response.result field.
589
+ Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v2/log_async).
590
+
591
+ Examples:
592
+ log_response = audit.log_bulk_async(
593
+ events=[{"message": "hello world"}],
594
+ verbose=True,
595
+ )
596
+ """
597
+
598
+ input = self._get_log_request(events, sign_local=sign_local, verify=False, verbose=verbose)
599
+
600
+ try:
601
+ # Calling to v2 methods will return always a 202.
602
+ response = self.request.post(
603
+ "v2/log_async", LogBulkResult, data=input.dict(exclude_none=True), poll_result=False
604
+ )
605
+ except pexc.AcceptedRequestException as e:
606
+ return e.response
607
+
608
+ if response.success:
609
+ for result in response.result.results:
610
+ self._process_log_result(result, verify=True)
611
+ return response
511
612
 
512
613
  def search(
513
614
  self,
@@ -558,11 +659,17 @@ class Audit(ServiceBase, AuditBase):
558
659
 
559
660
  Returns:
560
661
  A PangeaResponse[SearchOutput] where the first page of matched events is returned in the
561
- response.result field. Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#search-for-events).
562
- Pagination can be found in the [search results endpoint](https://pangea.cloud/docs/api/audit#search-results).
662
+ response.result field. Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#/v1/search).
663
+ Pagination can be found in the [search results endpoint](https://pangea.cloud/docs/api/audit#/v1/results).
563
664
 
564
665
  Examples:
565
- response: PangeaResponse[SearchOutput] = audit.search(query="message:test", search_restriction={'source': ["monitor"]}, limit=1, verify_consistency=True, verify_events=True)
666
+ response = audit.search(
667
+ query="message:test",
668
+ search_restriction={'source': ["monitor"]},
669
+ limit=1,
670
+ verify_consistency=True,
671
+ verify_events=True,
672
+ )
566
673
  """
567
674
 
568
675
  if verify_consistency:
@@ -609,17 +716,11 @@ class Audit(ServiceBase, AuditBase):
609
716
  PangeaAPIException: If an API Error happens
610
717
 
611
718
  Examples:
612
- search_res: PangeaResponse[SearchOutput] = audit.search(
613
- query="message:test",
614
- search_restriction={'source': ["monitor"]},
615
- limit=100,
616
- verify_consistency=True,
617
- verify_events=True)
618
-
619
- result_res: PangeaResponse[SearchResultsOutput] = audit.results(
620
- id=search_res.result.id,
719
+ response = audit.results(
720
+ id="pas_sqilrhruwu54uggihqj3aie24wrctakr",
621
721
  limit=10,
622
- offset=0)
722
+ offset=0,
723
+ )
623
724
  """
624
725
 
625
726
  if limit <= 0:
@@ -146,6 +146,34 @@ class LogRequest(APIRequestModel):
146
146
  prev_root: Optional[str] = None
147
147
 
148
148
 
149
+ class LogEvent(APIRequestModel):
150
+ """
151
+ Event to perform a log action
152
+
153
+ Arguments:
154
+ event -- A structured event describing an auditable activity.
155
+ signature -- An optional client-side signature for forgery protection.
156
+ public_key -- The base64-encoded ed25519 public key used for the signature, if one is provided.
157
+ """
158
+
159
+ event: Dict[str, Any]
160
+ signature: Optional[str] = None
161
+ public_key: Optional[str] = None
162
+
163
+
164
+ class LogBulkRequest(APIRequestModel):
165
+ """
166
+ Request to perform a bulk log action
167
+
168
+ Arguments:
169
+ events -- A list structured events describing an auditable activity.
170
+ verbose -- If true, be verbose in the response; include membership proof, unpublished root and consistency proof, etc.
171
+ """
172
+
173
+ events: List[LogEvent]
174
+ verbose: Optional[bool] = None
175
+
176
+
149
177
  class LogResult(PangeaResponseResult):
150
178
  """
151
179
  Result class after an audit log action
@@ -167,6 +195,10 @@ class LogResult(PangeaResponseResult):
167
195
  signature_verification: EventVerification = EventVerification.NONE
168
196
 
169
197
 
198
+ class LogBulkResult(PangeaResponseResult):
199
+ results: List[LogResult] = []
200
+
201
+
170
202
  class SearchRestriction(APIResponseModel):
171
203
  """
172
204
  Set of restrictions when perform an audit search action
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pangea-sdk"
3
- version = "3.1.0"
3
+ version = "3.2.0"
4
4
  description = "Pangea API SDK"
5
5
  authors = ["Glenn Gallien <glenn.gallien@pangea.cloud>"]
6
6
  license = "MIT"
File without changes
File without changes
File without changes
File without changes
File without changes