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.
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/PKG-INFO +1 -1
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/__init__.py +1 -1
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/audit.py +82 -3
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/exceptions.py +1 -1
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/response.py +6 -3
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/audit.py +163 -62
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/models.py +32 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pyproject.toml +1 -1
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/README.md +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/request.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/__init__.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/authn.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/base.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/embargo.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/file_scan.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/intel.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/redact.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/asyncio/services/vault.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/audit_logger.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/config.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/deep_verify.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/deprecated.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/dump_audit.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/request.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/__init__.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/exceptions.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/signing.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/audit/util.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/authn/authn.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/authn/models.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/base.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/embargo.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/file_scan.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/intel.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/redact.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/asymmetric.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/common.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/secret.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/models/symmetric.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/services/vault/vault.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/tools.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/utils.py +0 -0
- {pangea_sdk-3.1.0 → pangea_sdk-3.2.0}/pangea/verify_audit.py +0 -0
@@ -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.
|
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
|
-
|
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
|
148
|
-
|
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
|
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
|
-
|
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
|
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.
|
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
|
-
|
90
|
-
if not response.success:
|
91
|
-
return response
|
106
|
+
return LogEvent(event=event, signature=signature, public_key=pki)
|
92
107
|
|
93
|
-
|
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
|
112
|
+
if result.envelope:
|
97
113
|
# verify event hash
|
98
|
-
if
|
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.",
|
116
|
+
raise EventCorruption("Error: Event hash failed.", result.envelope)
|
101
117
|
|
102
|
-
|
118
|
+
result.signature_verification = self.verify_signature(result.envelope)
|
103
119
|
|
104
120
|
if new_unpublished_root_hash:
|
105
|
-
if
|
121
|
+
if result.membership_proof is not None:
|
106
122
|
# verify membership proofs
|
107
|
-
membership_proof = decode_membership_proof(
|
123
|
+
membership_proof = decode_membership_proof(result.membership_proof)
|
108
124
|
if verify_membership_proof(
|
109
|
-
node_hash=decode_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
|
-
|
129
|
+
result.membership_verification = EventVerification.PASS
|
114
130
|
else:
|
115
|
-
|
131
|
+
result.membership_verification = EventVerification.FAIL
|
116
132
|
|
117
133
|
# verify consistency proofs (following events)
|
118
|
-
if
|
119
|
-
consistency_proof = decode_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
|
-
|
141
|
+
result.consistency_verification = EventVerification.PASS
|
126
142
|
else:
|
127
|
-
|
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
|
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
|
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
|
-
|
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
|
461
|
+
[API documentation](https://pangea.cloud/docs/api/audit#/v1/log).
|
448
462
|
|
449
463
|
Examples:
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
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
|
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"
|
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.
|
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
|
-
|
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
|
562
|
-
Pagination can be found in the [search results endpoint](https://pangea.cloud/docs/api/audit
|
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
|
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
|
-
|
613
|
-
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|