prelude-cli-beta 1405__py3-none-any.whl → 1407__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.
Potentially problematic release.
This version of prelude-cli-beta might be problematic. Click here for more details.
- prelude_cli_beta/cli.py +52 -0
- prelude_cli_beta/views/auth.py +56 -0
- prelude_cli_beta/views/build.py +488 -0
- prelude_cli_beta/views/configure.py +29 -0
- prelude_cli_beta/views/detect.py +438 -0
- prelude_cli_beta/views/generate.py +125 -0
- prelude_cli_beta/views/iam.py +368 -0
- prelude_cli_beta/views/jobs.py +50 -0
- prelude_cli_beta/views/partner.py +192 -0
- prelude_cli_beta/views/scm.py +744 -0
- prelude_cli_beta/views/shared.py +37 -0
- prelude_cli_beta-1407.dist-info/METADATA +38 -0
- prelude_cli_beta-1407.dist-info/RECORD +20 -0
- prelude_cli_beta-1407.dist-info/entry_points.txt +3 -0
- prelude_cli_beta-1407.dist-info/top_level.txt +1 -0
- prelude_cli_beta-1405.dist-info/METADATA +0 -46
- prelude_cli_beta-1405.dist-info/RECORD +0 -20
- prelude_cli_beta-1405.dist-info/top_level.txt +0 -1
- prelude_sdk_beta/controllers/build_controller.py +0 -309
- prelude_sdk_beta/controllers/detect_controller.py +0 -243
- prelude_sdk_beta/controllers/export_controller.py +0 -31
- prelude_sdk_beta/controllers/generate_controller.py +0 -40
- prelude_sdk_beta/controllers/http_controller.py +0 -63
- prelude_sdk_beta/controllers/iam_controller.py +0 -278
- prelude_sdk_beta/controllers/jobs_controller.py +0 -26
- prelude_sdk_beta/controllers/partner_controller.py +0 -166
- prelude_sdk_beta/controllers/probe_controller.py +0 -14
- prelude_sdk_beta/controllers/scm_controller.py +0 -424
- prelude_sdk_beta/models/account.py +0 -264
- prelude_sdk_beta/models/codes.py +0 -446
- {prelude_sdk_beta → prelude_cli_beta}/__init__.py +0 -0
- {prelude_sdk_beta/controllers → prelude_cli_beta/templates}/__init__.py +0 -0
- {prelude_sdk_beta/models → prelude_cli_beta/views}/__init__.py +0 -0
- {prelude_cli_beta-1405.dist-info → prelude_cli_beta-1407.dist-info}/WHEEL +0 -0
- {prelude_cli_beta-1405.dist-info → prelude_cli_beta-1407.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
from rich import print_json
|
|
3
|
+
from rich.progress import Progress, TextColumn, SpinnerColumn
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def pretty_print(func):
|
|
7
|
+
@wraps(func)
|
|
8
|
+
def handler(*args, **kwargs):
|
|
9
|
+
try:
|
|
10
|
+
res = func(*args, **kwargs)
|
|
11
|
+
msg = None
|
|
12
|
+
if isinstance(res, tuple):
|
|
13
|
+
res, msg = res
|
|
14
|
+
if not isinstance(res, list):
|
|
15
|
+
res = [res]
|
|
16
|
+
return print_json(data=dict(status="complete", results=res, message=msg))
|
|
17
|
+
except Exception as e:
|
|
18
|
+
return print_json(
|
|
19
|
+
data=dict(
|
|
20
|
+
status="error",
|
|
21
|
+
results=None,
|
|
22
|
+
message=" ".join(str(arg) for arg in e.args),
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return handler
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Spinner(Progress):
|
|
30
|
+
def __init__(self, description="Loading"):
|
|
31
|
+
super().__init__(
|
|
32
|
+
SpinnerColumn(style="green", spinner_name="line"),
|
|
33
|
+
TextColumn("[green]{task.description}..."),
|
|
34
|
+
transient=True,
|
|
35
|
+
refresh_per_second=10,
|
|
36
|
+
)
|
|
37
|
+
self.add_task(description)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prelude-cli-beta
|
|
3
|
+
Version: 1407
|
|
4
|
+
Summary: For interacting with the Prelude SDK
|
|
5
|
+
Home-page: https://github.com/preludeorg
|
|
6
|
+
Author: Prelude Research
|
|
7
|
+
Author-email: support@preludesecurity.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: prelude-sdk-beta==1407
|
|
15
|
+
Requires-Dist: click>8
|
|
16
|
+
Requires-Dist: rich
|
|
17
|
+
Requires-Dist: python-dateutil
|
|
18
|
+
Requires-Dist: pyyaml
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# Prelude CLI
|
|
22
|
+
|
|
23
|
+
Interact with the full range of features in Prelude Detect, organized by:
|
|
24
|
+
|
|
25
|
+
- IAM: manage your account
|
|
26
|
+
- Build: write and maintain your collection of security tests
|
|
27
|
+
- Detect: schedule security tests for your endpoints
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
```bash
|
|
31
|
+
pip install prelude-cli
|
|
32
|
+
prelude --help
|
|
33
|
+
prelude --interactive
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
|
|
38
|
+
https://docs.preludesecurity.com/docs/prelude-cli
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
prelude_cli_beta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
prelude_cli_beta/cli.py,sha256=H3JbHuFxb46JbhsLZpH2I_5Vt9airCxUVGhqBAW6lIM,1454
|
|
3
|
+
prelude_cli_beta/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
prelude_cli_beta/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
prelude_cli_beta/views/auth.py,sha256=W-Bc6p3CXpHiQXJCQ4FoB3SdB9xIoeJlV4WMUezSBZ4,1864
|
|
6
|
+
prelude_cli_beta/views/build.py,sha256=olBRS2zjqxkvXKFmWLbqjKbbP_MDkwyjeAimHGRyfvw,16508
|
|
7
|
+
prelude_cli_beta/views/configure.py,sha256=saj0kR9mQqBp7cCmq-yfEr3UwZCZIV1vL8WDQLDAO7o,991
|
|
8
|
+
prelude_cli_beta/views/detect.py,sha256=jhx38nTRjZwxPAN4QbjyMkmk1mZDqZGh4uKPyG_FZ1s,13012
|
|
9
|
+
prelude_cli_beta/views/generate.py,sha256=hfrlmRkb6aSo4LPaPVLhTRUFm8cxZwDqTEjLEPMlBMU,4679
|
|
10
|
+
prelude_cli_beta/views/iam.py,sha256=J8y6kJGbQkEexcia69q6vLJ3aEhLyUFteCylTptBHBQ,10013
|
|
11
|
+
prelude_cli_beta/views/jobs.py,sha256=2FeiJxHrw4zfgtUJq_bEoG84i_9TqZ5w6CulA80WoNA,1455
|
|
12
|
+
prelude_cli_beta/views/partner.py,sha256=16zXcX5ZhiNZqKSXG9ePPGB9K3A-OgrVIdJGDJhB6f0,6379
|
|
13
|
+
prelude_cli_beta/views/scm.py,sha256=DKIl9DjVNmShphD5LDHRBP_BLZAbm8CBuU8PI3gUxjY,21617
|
|
14
|
+
prelude_cli_beta/views/shared.py,sha256=ZKvY8N1Vi6RtEbJli5PDzJ9R6L_bX2F27n1tm6Knvgs,1101
|
|
15
|
+
prelude_cli_beta-1407.dist-info/licenses/LICENSE,sha256=ttdT5omfN6LNmtQoIjUhkkFhz6i44SDMRNwKrbfyTf8,1069
|
|
16
|
+
prelude_cli_beta-1407.dist-info/METADATA,sha256=Q_5LBqVGpbz0pFHtUghXGxq9B5GKHeVSbZ7QdKLGjT4,993
|
|
17
|
+
prelude_cli_beta-1407.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
+
prelude_cli_beta-1407.dist-info/entry_points.txt,sha256=WowrC6fz2D6S8S-5OY0g-bxUGGSZZ_Z6KzSXXd34pC4,88
|
|
19
|
+
prelude_cli_beta-1407.dist-info/top_level.txt,sha256=j50aCGsQamLMiQh9PcolDBCAeUJzi9y08e0i9Gqshkk,17
|
|
20
|
+
prelude_cli_beta-1407.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prelude_cli_beta
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: prelude-cli-beta
|
|
3
|
-
Version: 1405
|
|
4
|
-
Summary: For interacting with the Prelude API
|
|
5
|
-
Home-page: https://github.com/preludeorg
|
|
6
|
-
Author: Prelude Research
|
|
7
|
-
Author-email: support@preludesecurity.com
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.10
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: requests
|
|
15
|
-
Dynamic: license-file
|
|
16
|
-
|
|
17
|
-
# Prelude SDK
|
|
18
|
-
|
|
19
|
-
Interact with the Prelude Service API via Python.
|
|
20
|
-
|
|
21
|
-
> The prelude-cli utility wraps around this SDK to provide a rich command line experience.
|
|
22
|
-
|
|
23
|
-
Install this package to write your own tooling that works with Build or Detect functionality.
|
|
24
|
-
|
|
25
|
-
- IAM: manage your account
|
|
26
|
-
- Build: write and maintain your collection of security tests
|
|
27
|
-
- Detect: schedule security tests for your endpoints
|
|
28
|
-
|
|
29
|
-
## Quick start
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pip install prelude-sdk
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Documentation
|
|
36
|
-
|
|
37
|
-
TBD
|
|
38
|
-
|
|
39
|
-
## Testing
|
|
40
|
-
|
|
41
|
-
To test the Python SDK and Probes, run the following commands from the python/sdk/ directory:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
pip install -r tests/requirements.txt
|
|
45
|
-
pytest tests --api https://api.preludesecurity.com --email <EMAIL>
|
|
46
|
-
```
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
prelude_cli_beta-1405.dist-info/licenses/LICENSE,sha256=ttdT5omfN6LNmtQoIjUhkkFhz6i44SDMRNwKrbfyTf8,1069
|
|
2
|
-
prelude_sdk_beta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
prelude_sdk_beta/controllers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
prelude_sdk_beta/controllers/build_controller.py,sha256=tMWMMp7SttZl9rnja_mMkkRRApLOSAjBBZKFrsXPR7c,8802
|
|
5
|
-
prelude_sdk_beta/controllers/detect_controller.py,sha256=zB30PESzSqds8bNG2FKxM9miwO0PponTk9XWfZ4WvPA,7499
|
|
6
|
-
prelude_sdk_beta/controllers/export_controller.py,sha256=lIRmO7b2sMLyA8WAsGFqtXuCp79r25zgopJGM5KnxvA,847
|
|
7
|
-
prelude_sdk_beta/controllers/generate_controller.py,sha256=JUYlBdMh8alSMvin32qb3hB1JNGbT-BarEgxhMhg9PI,1304
|
|
8
|
-
prelude_sdk_beta/controllers/http_controller.py,sha256=cj1SxmAX049ioAhTOQR4atuM82nJgd11S60-ISCg738,2300
|
|
9
|
-
prelude_sdk_beta/controllers/iam_controller.py,sha256=eDT0kw1IfA_enQF_1kC_vSWS7-LFL9PO24EoxxM8Ax4,7856
|
|
10
|
-
prelude_sdk_beta/controllers/jobs_controller.py,sha256=Ekf41oD72gBJeEfSfGYUfxpsQI-SUqY8EdtBmzqEIM0,755
|
|
11
|
-
prelude_sdk_beta/controllers/partner_controller.py,sha256=T4D3Nl1SF6OLIiGPR81cPGAxUd4GSnKZ9Jl-rbAHZFE,5113
|
|
12
|
-
prelude_sdk_beta/controllers/probe_controller.py,sha256=rwBnqkFJa1KuVwZMluM-pfo8bhQFB6JKSRSeK7s-kew,406
|
|
13
|
-
prelude_sdk_beta/controllers/scm_controller.py,sha256=l30RZa4X19nBm6E411kAT36LM1CDl15Bd0yC3_jUb80,12778
|
|
14
|
-
prelude_sdk_beta/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
prelude_sdk_beta/models/account.py,sha256=ksyTZDOZpbT8XDu-Ygs_51ZG25oBd8qiwjO6-L6HH9Y,8734
|
|
16
|
-
prelude_sdk_beta/models/codes.py,sha256=-gxBflkV-RdE3LwGSDDSO48eK-J8skZ5CivMD2MYc5w,11425
|
|
17
|
-
prelude_cli_beta-1405.dist-info/METADATA,sha256=fBpqVU1UPe3eZAb9WL7FPXfB8A4FA4f2iQZZ2pNblwo,1190
|
|
18
|
-
prelude_cli_beta-1405.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
19
|
-
prelude_cli_beta-1405.dist-info/top_level.txt,sha256=pqXTtEd5ElvJKoO6HAz232H9FW5j6X7gW4kEEakfSFM,17
|
|
20
|
-
prelude_cli_beta-1405.dist-info/RECORD,,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
prelude_sdk_beta
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import urllib
|
|
2
|
-
|
|
3
|
-
from prelude_sdk.controllers.http_controller import HttpController
|
|
4
|
-
from prelude_sdk.models.account import verify_credentials
|
|
5
|
-
from prelude_sdk.models.codes import Control, EDRResponse
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class BuildController(HttpController):
|
|
9
|
-
|
|
10
|
-
def __init__(self, account):
|
|
11
|
-
super().__init__(account)
|
|
12
|
-
|
|
13
|
-
@verify_credentials
|
|
14
|
-
def clone_test(self, source_test_id):
|
|
15
|
-
"""Clone a test"""
|
|
16
|
-
res = self.post(
|
|
17
|
-
f"{self.account.hq}/build/tests",
|
|
18
|
-
json=dict(source_test_id=source_test_id),
|
|
19
|
-
headers=self.account.headers,
|
|
20
|
-
timeout=10,
|
|
21
|
-
)
|
|
22
|
-
return res.json()
|
|
23
|
-
|
|
24
|
-
@verify_credentials
|
|
25
|
-
def create_test(self, name, unit, technique=None, test_id=None):
|
|
26
|
-
"""Create or update a test"""
|
|
27
|
-
body = dict(name=name, unit=unit)
|
|
28
|
-
if technique:
|
|
29
|
-
body["technique"] = technique
|
|
30
|
-
if test_id:
|
|
31
|
-
body["id"] = test_id
|
|
32
|
-
|
|
33
|
-
res = self.post(
|
|
34
|
-
f"{self.account.hq}/build/tests",
|
|
35
|
-
json=body,
|
|
36
|
-
headers=self.account.headers,
|
|
37
|
-
timeout=10,
|
|
38
|
-
)
|
|
39
|
-
return res.json()
|
|
40
|
-
|
|
41
|
-
@verify_credentials
|
|
42
|
-
def update_test(
|
|
43
|
-
self,
|
|
44
|
-
test_id,
|
|
45
|
-
name=None,
|
|
46
|
-
unit=None,
|
|
47
|
-
technique=None,
|
|
48
|
-
crowdstrike_expected_outcome: EDRResponse = None,
|
|
49
|
-
):
|
|
50
|
-
"""Update a test"""
|
|
51
|
-
body = dict()
|
|
52
|
-
if crowdstrike_expected_outcome:
|
|
53
|
-
body["expected"] = dict(crowdstrike=crowdstrike_expected_outcome.value)
|
|
54
|
-
if name:
|
|
55
|
-
body["name"] = name
|
|
56
|
-
if unit:
|
|
57
|
-
body["unit"] = unit
|
|
58
|
-
if technique is not None:
|
|
59
|
-
body["technique"] = technique
|
|
60
|
-
|
|
61
|
-
res = self.post(
|
|
62
|
-
f"{self.account.hq}/build/tests/{test_id}",
|
|
63
|
-
json=body,
|
|
64
|
-
headers=self.account.headers,
|
|
65
|
-
timeout=10,
|
|
66
|
-
)
|
|
67
|
-
return res.json()
|
|
68
|
-
|
|
69
|
-
@verify_credentials
|
|
70
|
-
def delete_test(self, test_id, purge):
|
|
71
|
-
"""Delete an existing test"""
|
|
72
|
-
res = self.delete(
|
|
73
|
-
f"{self.account.hq}/build/tests/{test_id}",
|
|
74
|
-
json=dict(purge=purge),
|
|
75
|
-
headers=self.account.headers,
|
|
76
|
-
timeout=10,
|
|
77
|
-
)
|
|
78
|
-
return res.json()
|
|
79
|
-
|
|
80
|
-
@verify_credentials
|
|
81
|
-
def undelete_test(self, test_id):
|
|
82
|
-
"""Undelete a tombstoned test"""
|
|
83
|
-
res = self.post(
|
|
84
|
-
f"{self.account.hq}/build/tests/{test_id}/undelete",
|
|
85
|
-
headers=self.account.headers,
|
|
86
|
-
timeout=10,
|
|
87
|
-
)
|
|
88
|
-
return res.json()
|
|
89
|
-
|
|
90
|
-
@verify_credentials
|
|
91
|
-
def upload(self, test_id, filename, data, skip_compile=False):
|
|
92
|
-
"""Upload a test or attachment"""
|
|
93
|
-
if len(data) > 1000000:
|
|
94
|
-
raise ValueError(f"File size must be under 1MB ({filename})")
|
|
95
|
-
|
|
96
|
-
h = self.account.headers | {"Content-Type": "application/octet-stream"}
|
|
97
|
-
query_params = ""
|
|
98
|
-
if skip_compile:
|
|
99
|
-
query_params = "?" + urllib.parse.urlencode(dict(skip_compile=True))
|
|
100
|
-
res = self.post(
|
|
101
|
-
f"{self.account.hq}/build/tests/{test_id}/{filename}{query_params}",
|
|
102
|
-
data=data,
|
|
103
|
-
headers=h,
|
|
104
|
-
timeout=10,
|
|
105
|
-
)
|
|
106
|
-
return res.json()
|
|
107
|
-
|
|
108
|
-
@verify_credentials
|
|
109
|
-
def compile_code_string(self, code: str, source_test_id: str = None):
|
|
110
|
-
"""Compile a code string"""
|
|
111
|
-
res = self.post(
|
|
112
|
-
f"{self.account.hq}/build/compile",
|
|
113
|
-
json=dict(code=code, source_test_id=source_test_id),
|
|
114
|
-
headers=self.account.headers,
|
|
115
|
-
timeout=10,
|
|
116
|
-
)
|
|
117
|
-
return res.json()
|
|
118
|
-
|
|
119
|
-
@verify_credentials
|
|
120
|
-
def get_compile_status(self, job_id):
|
|
121
|
-
res = self.get(
|
|
122
|
-
f"{self.account.hq}/build/compile/{job_id}",
|
|
123
|
-
headers=self.account.headers,
|
|
124
|
-
timeout=10,
|
|
125
|
-
)
|
|
126
|
-
return res.json()
|
|
127
|
-
|
|
128
|
-
@verify_credentials
|
|
129
|
-
def create_threat(
|
|
130
|
-
self, name, published, threat_id=None, source_id=None, source=None, tests=None
|
|
131
|
-
):
|
|
132
|
-
"""Create a threat"""
|
|
133
|
-
body = dict(name=name, published=published)
|
|
134
|
-
if threat_id:
|
|
135
|
-
body["id"] = threat_id
|
|
136
|
-
if source_id:
|
|
137
|
-
body["source_id"] = source_id
|
|
138
|
-
if source:
|
|
139
|
-
body["source"] = source
|
|
140
|
-
if tests:
|
|
141
|
-
body["tests"] = tests
|
|
142
|
-
|
|
143
|
-
res = self.post(
|
|
144
|
-
f"{self.account.hq}/build/threats",
|
|
145
|
-
json=body,
|
|
146
|
-
headers=self.account.headers,
|
|
147
|
-
timeout=10,
|
|
148
|
-
)
|
|
149
|
-
return res.json()
|
|
150
|
-
|
|
151
|
-
@verify_credentials
|
|
152
|
-
def update_threat(
|
|
153
|
-
self,
|
|
154
|
-
threat_id,
|
|
155
|
-
name=None,
|
|
156
|
-
source_id=None,
|
|
157
|
-
source=None,
|
|
158
|
-
published=None,
|
|
159
|
-
tests=None,
|
|
160
|
-
):
|
|
161
|
-
"""Update a threat"""
|
|
162
|
-
body = dict()
|
|
163
|
-
if name:
|
|
164
|
-
body["name"] = name
|
|
165
|
-
if source_id is not None:
|
|
166
|
-
body["source_id"] = source_id
|
|
167
|
-
if source is not None:
|
|
168
|
-
body["source"] = source
|
|
169
|
-
if published is not None:
|
|
170
|
-
body["published"] = published
|
|
171
|
-
if tests is not None:
|
|
172
|
-
body["tests"] = tests
|
|
173
|
-
|
|
174
|
-
res = self.post(
|
|
175
|
-
f"{self.account.hq}/build/threats/{threat_id}",
|
|
176
|
-
json=body,
|
|
177
|
-
headers=self.account.headers,
|
|
178
|
-
timeout=10,
|
|
179
|
-
)
|
|
180
|
-
return res.json()
|
|
181
|
-
|
|
182
|
-
@verify_credentials
|
|
183
|
-
def delete_threat(self, threat_id, purge):
|
|
184
|
-
"""Delete an existing threat"""
|
|
185
|
-
res = self.delete(
|
|
186
|
-
f"{self.account.hq}/build/threats/{threat_id}",
|
|
187
|
-
json=dict(purge=purge),
|
|
188
|
-
headers=self.account.headers,
|
|
189
|
-
timeout=10,
|
|
190
|
-
)
|
|
191
|
-
return res.json()
|
|
192
|
-
|
|
193
|
-
@verify_credentials
|
|
194
|
-
def undelete_threat(self, threat_id):
|
|
195
|
-
"""Undelete a tombstoned threat"""
|
|
196
|
-
res = self.post(
|
|
197
|
-
f"{self.account.hq}/build/threats/{threat_id}/undelete",
|
|
198
|
-
headers=self.account.headers,
|
|
199
|
-
timeout=10,
|
|
200
|
-
)
|
|
201
|
-
return res.json()
|
|
202
|
-
|
|
203
|
-
@verify_credentials
|
|
204
|
-
def create_detection(
|
|
205
|
-
self, rule: str, test_id: str, detection_id=None, rule_id=None
|
|
206
|
-
):
|
|
207
|
-
"""Create a detection"""
|
|
208
|
-
body = dict(rule=rule, test_id=test_id)
|
|
209
|
-
if detection_id:
|
|
210
|
-
body["detection_id"] = detection_id
|
|
211
|
-
if rule_id:
|
|
212
|
-
body["rule_id"] = rule_id
|
|
213
|
-
|
|
214
|
-
res = self.post(
|
|
215
|
-
f"{self.account.hq}/build/detections",
|
|
216
|
-
json=body,
|
|
217
|
-
headers=self.account.headers,
|
|
218
|
-
timeout=10,
|
|
219
|
-
)
|
|
220
|
-
return res.json()
|
|
221
|
-
|
|
222
|
-
@verify_credentials
|
|
223
|
-
def update_detection(self, detection_id: str, rule=None, test_id=None):
|
|
224
|
-
"""Update a detection"""
|
|
225
|
-
body = dict()
|
|
226
|
-
if rule:
|
|
227
|
-
body["rule"] = rule
|
|
228
|
-
if test_id:
|
|
229
|
-
body["test_id"] = test_id
|
|
230
|
-
|
|
231
|
-
res = self.post(
|
|
232
|
-
f"{self.account.hq}/build/detections/{detection_id}",
|
|
233
|
-
json=body,
|
|
234
|
-
headers=self.account.headers,
|
|
235
|
-
timeout=10,
|
|
236
|
-
)
|
|
237
|
-
return res.json()
|
|
238
|
-
|
|
239
|
-
@verify_credentials
|
|
240
|
-
def delete_detection(self, detection_id: str):
|
|
241
|
-
"""Delete an existing detection"""
|
|
242
|
-
res = self.delete(
|
|
243
|
-
f"{self.account.hq}/build/detections/{detection_id}",
|
|
244
|
-
headers=self.account.headers,
|
|
245
|
-
timeout=10,
|
|
246
|
-
)
|
|
247
|
-
return res.json()
|
|
248
|
-
|
|
249
|
-
@verify_credentials
|
|
250
|
-
def create_threat_hunt(
|
|
251
|
-
self,
|
|
252
|
-
control: Control,
|
|
253
|
-
test_id: str,
|
|
254
|
-
name: str,
|
|
255
|
-
query: str,
|
|
256
|
-
threat_hunt_id: str = None,
|
|
257
|
-
):
|
|
258
|
-
"""Create a threat hunt"""
|
|
259
|
-
body = dict(
|
|
260
|
-
control=control.name,
|
|
261
|
-
name=name,
|
|
262
|
-
query=query,
|
|
263
|
-
test_id=test_id,
|
|
264
|
-
)
|
|
265
|
-
if threat_hunt_id:
|
|
266
|
-
body["id"] = threat_hunt_id
|
|
267
|
-
|
|
268
|
-
res = self.post(
|
|
269
|
-
f"{self.account.hq}/build/threat_hunts",
|
|
270
|
-
json=body,
|
|
271
|
-
headers=self.account.headers,
|
|
272
|
-
timeout=10,
|
|
273
|
-
)
|
|
274
|
-
return res.json()
|
|
275
|
-
|
|
276
|
-
@verify_credentials
|
|
277
|
-
def update_threat_hunt(
|
|
278
|
-
self,
|
|
279
|
-
threat_hunt_id: str,
|
|
280
|
-
name: str = None,
|
|
281
|
-
query: str = None,
|
|
282
|
-
test_id: str = None,
|
|
283
|
-
):
|
|
284
|
-
"""Update a threat hunt"""
|
|
285
|
-
body = dict()
|
|
286
|
-
if name:
|
|
287
|
-
body["name"] = name
|
|
288
|
-
if query:
|
|
289
|
-
body["query"] = query
|
|
290
|
-
if test_id:
|
|
291
|
-
body["test_id"] = test_id
|
|
292
|
-
|
|
293
|
-
res = self.post(
|
|
294
|
-
f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}",
|
|
295
|
-
json=body,
|
|
296
|
-
headers=self.account.headers,
|
|
297
|
-
timeout=10,
|
|
298
|
-
)
|
|
299
|
-
return res.json()
|
|
300
|
-
|
|
301
|
-
@verify_credentials
|
|
302
|
-
def delete_threat_hunt(self, threat_hunt_id: str):
|
|
303
|
-
"""Delete an existing threat hunt"""
|
|
304
|
-
res = self.delete(
|
|
305
|
-
f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}",
|
|
306
|
-
headers=self.account.headers,
|
|
307
|
-
timeout=10,
|
|
308
|
-
)
|
|
309
|
-
return res.json()
|