prelude-sdk 2.6.39__tar.gz → 2.6.41__tar.gz
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.
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/PKG-INFO +1 -1
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/build_controller.py +49 -100
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/detect_controller.py +33 -102
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/export_controller.py +3 -7
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/generate_controller.py +3 -6
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/http_controller.py +28 -12
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/iam_controller.py +20 -99
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/jobs_controller.py +2 -8
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/partner_controller.py +13 -30
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/probe_controller.py +1 -3
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/scm_controller.py +67 -183
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/models/codes.py +21 -15
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk.egg-info/PKG-INFO +1 -1
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/setup.cfg +1 -1
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_scm.py +11 -16
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_scm_build.py +5 -3
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/LICENSE +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/README.md +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/__init__.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/controllers/__init__.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/models/__init__.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk/models/account.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk.egg-info/SOURCES.txt +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk.egg-info/dependency_links.txt +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk.egg-info/requires.txt +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/prelude_sdk.egg-info/top_level.txt +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/pyproject.toml +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_build.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_detect.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_generate.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_iam.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_partner.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/test_probe.py +0 -0
- {prelude_sdk-2.6.39 → prelude_sdk-2.6.41}/tests/testutils.py +0 -0
|
@@ -14,38 +14,33 @@ class BuildController(HttpController):
|
|
|
14
14
|
def clone_test(self, source_test_id):
|
|
15
15
|
"""Clone a test"""
|
|
16
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,
|
|
17
|
+
f"{self.account.hq}/build/tests", json=dict(source_test_id=source_test_id)
|
|
21
18
|
)
|
|
22
19
|
return res.json()
|
|
23
20
|
|
|
24
21
|
@verify_credentials
|
|
25
|
-
def create_test(self, name, unit, technique=None, test_id=None):
|
|
22
|
+
def create_test(self, name, unit, schedulable=None, technique=None, test_id=None):
|
|
26
23
|
"""Create or update a test"""
|
|
27
24
|
body = dict(name=name, unit=unit)
|
|
25
|
+
if schedulable is not None:
|
|
26
|
+
body["schedulable"] = schedulable
|
|
28
27
|
if technique:
|
|
29
28
|
body["technique"] = technique
|
|
30
29
|
if test_id:
|
|
31
30
|
body["id"] = test_id
|
|
32
31
|
|
|
33
|
-
res = self.post(
|
|
34
|
-
f"{self.account.hq}/build/tests",
|
|
35
|
-
json=body,
|
|
36
|
-
headers=self.account.headers,
|
|
37
|
-
timeout=10,
|
|
38
|
-
)
|
|
32
|
+
res = self.post(f"{self.account.hq}/build/tests", json=body)
|
|
39
33
|
return res.json()
|
|
40
34
|
|
|
41
35
|
@verify_credentials
|
|
42
36
|
def update_test(
|
|
43
37
|
self,
|
|
44
38
|
test_id,
|
|
39
|
+
crowdstrike_expected_outcome: EDRResponse = None,
|
|
45
40
|
name=None,
|
|
46
|
-
|
|
41
|
+
schedulable=None,
|
|
47
42
|
technique=None,
|
|
48
|
-
|
|
43
|
+
unit=None,
|
|
49
44
|
):
|
|
50
45
|
"""Update a test"""
|
|
51
46
|
body = dict()
|
|
@@ -53,38 +48,28 @@ class BuildController(HttpController):
|
|
|
53
48
|
body["expected"] = dict(crowdstrike=crowdstrike_expected_outcome.value)
|
|
54
49
|
if name:
|
|
55
50
|
body["name"] = name
|
|
56
|
-
if
|
|
57
|
-
body["
|
|
51
|
+
if schedulable is not None:
|
|
52
|
+
body["schedulable"] = schedulable
|
|
58
53
|
if technique is not None:
|
|
59
54
|
body["technique"] = technique
|
|
55
|
+
if unit:
|
|
56
|
+
body["unit"] = unit
|
|
60
57
|
|
|
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
|
-
)
|
|
58
|
+
res = self.post(f"{self.account.hq}/build/tests/{test_id}", json=body)
|
|
67
59
|
return res.json()
|
|
68
60
|
|
|
69
61
|
@verify_credentials
|
|
70
62
|
def delete_test(self, test_id, purge):
|
|
71
63
|
"""Delete an existing test"""
|
|
72
64
|
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,
|
|
65
|
+
f"{self.account.hq}/build/tests/{test_id}", json=dict(purge=purge)
|
|
77
66
|
)
|
|
78
67
|
return res.json()
|
|
79
68
|
|
|
80
69
|
@verify_credentials
|
|
81
70
|
def undelete_test(self, test_id):
|
|
82
71
|
"""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
|
-
)
|
|
72
|
+
res = self.post(f"{self.account.hq}/build/tests/{test_id}/undelete")
|
|
88
73
|
return res.json()
|
|
89
74
|
|
|
90
75
|
@verify_credentials
|
|
@@ -97,11 +82,11 @@ class BuildController(HttpController):
|
|
|
97
82
|
query_params = ""
|
|
98
83
|
if skip_compile:
|
|
99
84
|
query_params = "?" + urllib.parse.urlencode(dict(skip_compile=True))
|
|
85
|
+
|
|
100
86
|
res = self.post(
|
|
101
87
|
f"{self.account.hq}/build/tests/{test_id}/{filename}{query_params}",
|
|
102
88
|
data=data,
|
|
103
89
|
headers=h,
|
|
104
|
-
timeout=10,
|
|
105
90
|
)
|
|
106
91
|
return res.json()
|
|
107
92
|
|
|
@@ -111,41 +96,39 @@ class BuildController(HttpController):
|
|
|
111
96
|
res = self.post(
|
|
112
97
|
f"{self.account.hq}/build/compile",
|
|
113
98
|
json=dict(code=code, source_test_id=source_test_id),
|
|
114
|
-
headers=self.account.headers,
|
|
115
|
-
timeout=10,
|
|
116
99
|
)
|
|
117
100
|
return res.json()
|
|
118
101
|
|
|
119
102
|
@verify_credentials
|
|
120
103
|
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
|
-
)
|
|
104
|
+
res = self.get(f"{self.account.hq}/build/compile/{job_id}")
|
|
126
105
|
return res.json()
|
|
127
106
|
|
|
128
107
|
@verify_credentials
|
|
129
108
|
def create_threat(
|
|
130
|
-
self,
|
|
109
|
+
self,
|
|
110
|
+
name,
|
|
111
|
+
published,
|
|
112
|
+
schedulable=None,
|
|
113
|
+
source=None,
|
|
114
|
+
source_id=None,
|
|
115
|
+
tests=None,
|
|
116
|
+
threat_id=None,
|
|
131
117
|
):
|
|
132
118
|
"""Create a threat"""
|
|
133
119
|
body = dict(name=name, published=published)
|
|
134
|
-
if
|
|
135
|
-
body["
|
|
136
|
-
if source_id:
|
|
137
|
-
body["source_id"] = source_id
|
|
120
|
+
if schedulable is not None:
|
|
121
|
+
body["schedulable"] = schedulable
|
|
138
122
|
if source:
|
|
139
123
|
body["source"] = source
|
|
124
|
+
if source_id:
|
|
125
|
+
body["source_id"] = source_id
|
|
140
126
|
if tests:
|
|
141
127
|
body["tests"] = tests
|
|
128
|
+
if threat_id:
|
|
129
|
+
body["id"] = threat_id
|
|
142
130
|
|
|
143
|
-
res = self.post(
|
|
144
|
-
f"{self.account.hq}/build/threats",
|
|
145
|
-
json=body,
|
|
146
|
-
headers=self.account.headers,
|
|
147
|
-
timeout=10,
|
|
148
|
-
)
|
|
131
|
+
res = self.post(f"{self.account.hq}/build/threats", json=body)
|
|
149
132
|
return res.json()
|
|
150
133
|
|
|
151
134
|
@verify_credentials
|
|
@@ -153,30 +136,28 @@ class BuildController(HttpController):
|
|
|
153
136
|
self,
|
|
154
137
|
threat_id,
|
|
155
138
|
name=None,
|
|
156
|
-
source_id=None,
|
|
157
|
-
source=None,
|
|
158
139
|
published=None,
|
|
140
|
+
schedulable=None,
|
|
141
|
+
source=None,
|
|
142
|
+
source_id=None,
|
|
159
143
|
tests=None,
|
|
160
144
|
):
|
|
161
145
|
"""Update a threat"""
|
|
162
146
|
body = dict()
|
|
163
147
|
if name:
|
|
164
148
|
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
149
|
if published is not None:
|
|
170
150
|
body["published"] = published
|
|
151
|
+
if schedulable is not None:
|
|
152
|
+
body["schedulable"] = schedulable
|
|
153
|
+
if source is not None:
|
|
154
|
+
body["source"] = source
|
|
155
|
+
if source_id is not None:
|
|
156
|
+
body["source_id"] = source_id
|
|
171
157
|
if tests is not None:
|
|
172
158
|
body["tests"] = tests
|
|
173
159
|
|
|
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
|
-
)
|
|
160
|
+
res = self.post(f"{self.account.hq}/build/threats/{threat_id}", json=body)
|
|
180
161
|
return res.json()
|
|
181
162
|
|
|
182
163
|
@verify_credentials
|
|
@@ -185,19 +166,13 @@ class BuildController(HttpController):
|
|
|
185
166
|
res = self.delete(
|
|
186
167
|
f"{self.account.hq}/build/threats/{threat_id}",
|
|
187
168
|
json=dict(purge=purge),
|
|
188
|
-
headers=self.account.headers,
|
|
189
|
-
timeout=10,
|
|
190
169
|
)
|
|
191
170
|
return res.json()
|
|
192
171
|
|
|
193
172
|
@verify_credentials
|
|
194
173
|
def undelete_threat(self, threat_id):
|
|
195
174
|
"""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
|
-
)
|
|
175
|
+
res = self.post(f"{self.account.hq}/build/threats/{threat_id}/undelete")
|
|
201
176
|
return res.json()
|
|
202
177
|
|
|
203
178
|
@verify_credentials
|
|
@@ -211,12 +186,7 @@ class BuildController(HttpController):
|
|
|
211
186
|
if rule_id:
|
|
212
187
|
body["rule_id"] = rule_id
|
|
213
188
|
|
|
214
|
-
res = self.post(
|
|
215
|
-
f"{self.account.hq}/build/detections",
|
|
216
|
-
json=body,
|
|
217
|
-
headers=self.account.headers,
|
|
218
|
-
timeout=10,
|
|
219
|
-
)
|
|
189
|
+
res = self.post(f"{self.account.hq}/build/detections", json=body)
|
|
220
190
|
return res.json()
|
|
221
191
|
|
|
222
192
|
@verify_credentials
|
|
@@ -228,22 +198,13 @@ class BuildController(HttpController):
|
|
|
228
198
|
if test_id:
|
|
229
199
|
body["test_id"] = test_id
|
|
230
200
|
|
|
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
|
-
)
|
|
201
|
+
res = self.post(f"{self.account.hq}/build/detections/{detection_id}", json=body)
|
|
237
202
|
return res.json()
|
|
238
203
|
|
|
239
204
|
@verify_credentials
|
|
240
205
|
def delete_detection(self, detection_id: str):
|
|
241
206
|
"""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
|
-
)
|
|
207
|
+
res = self.delete(f"{self.account.hq}/build/detections/{detection_id}")
|
|
247
208
|
return res.json()
|
|
248
209
|
|
|
249
210
|
@verify_credentials
|
|
@@ -265,12 +226,7 @@ class BuildController(HttpController):
|
|
|
265
226
|
if threat_hunt_id:
|
|
266
227
|
body["id"] = threat_hunt_id
|
|
267
228
|
|
|
268
|
-
res = self.post(
|
|
269
|
-
f"{self.account.hq}/build/threat_hunts",
|
|
270
|
-
json=body,
|
|
271
|
-
headers=self.account.headers,
|
|
272
|
-
timeout=10,
|
|
273
|
-
)
|
|
229
|
+
res = self.post(f"{self.account.hq}/build/threat_hunts", json=body)
|
|
274
230
|
threat_hunt = res.json()
|
|
275
231
|
if self.account.resolve_enums:
|
|
276
232
|
self.resolve_enums(threat_hunt, [(Control, "control")])
|
|
@@ -294,10 +250,7 @@ class BuildController(HttpController):
|
|
|
294
250
|
body["test_id"] = test_id
|
|
295
251
|
|
|
296
252
|
res = self.post(
|
|
297
|
-
f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}",
|
|
298
|
-
json=body,
|
|
299
|
-
headers=self.account.headers,
|
|
300
|
-
timeout=10,
|
|
253
|
+
f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}", json=body
|
|
301
254
|
)
|
|
302
255
|
threat_hunt = res.json()
|
|
303
256
|
if self.account.resolve_enums:
|
|
@@ -307,9 +260,5 @@ class BuildController(HttpController):
|
|
|
307
260
|
@verify_credentials
|
|
308
261
|
def delete_threat_hunt(self, threat_hunt_id: str):
|
|
309
262
|
"""Delete an existing threat hunt"""
|
|
310
|
-
res = self.delete(
|
|
311
|
-
f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}",
|
|
312
|
-
headers=self.account.headers,
|
|
313
|
-
timeout=10,
|
|
314
|
-
)
|
|
263
|
+
res = self.delete(f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}")
|
|
315
264
|
return res.json()
|
|
@@ -19,7 +19,6 @@ class DetectController(HttpController):
|
|
|
19
19
|
f"{self.account.hq}/detect/endpoint",
|
|
20
20
|
headers=dict(account=account, token=token, _product="py-sdk"),
|
|
21
21
|
json=body,
|
|
22
|
-
timeout=10,
|
|
23
22
|
)
|
|
24
23
|
return res.text
|
|
25
24
|
|
|
@@ -30,36 +29,23 @@ class DetectController(HttpController):
|
|
|
30
29
|
if tags is not None:
|
|
31
30
|
body["tags"] = tags
|
|
32
31
|
|
|
33
|
-
res = self.post(
|
|
34
|
-
f"{self.account.hq}/detect/endpoint/{endpoint_id}",
|
|
35
|
-
headers=self.account.headers,
|
|
36
|
-
json=body,
|
|
37
|
-
timeout=10,
|
|
38
|
-
)
|
|
32
|
+
res = self.post(f"{self.account.hq}/detect/endpoint/{endpoint_id}", json=body)
|
|
39
33
|
return res.json()
|
|
40
34
|
|
|
41
35
|
@verify_credentials
|
|
42
36
|
def delete_endpoint(self, ident: str):
|
|
43
37
|
"""Delete an endpoint from your account"""
|
|
44
38
|
params = dict(id=ident)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
headers=self.account.headers,
|
|
48
|
-
json=params,
|
|
49
|
-
timeout=10,
|
|
50
|
-
)
|
|
39
|
+
|
|
40
|
+
res = self.delete(f"{self.account.hq}/detect/endpoint", json=params)
|
|
51
41
|
return res.json()
|
|
52
42
|
|
|
53
43
|
@verify_credentials
|
|
54
44
|
def list_endpoints(self, days: int = 90):
|
|
55
45
|
"""List all endpoints on your account"""
|
|
56
46
|
params = dict(days=days)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
headers=self.account.headers,
|
|
60
|
-
params=params,
|
|
61
|
-
timeout=10,
|
|
62
|
-
)
|
|
47
|
+
|
|
48
|
+
res = self.get(f"{self.account.hq}/detect/endpoint", params=params)
|
|
63
49
|
endpoints = res.json()
|
|
64
50
|
if self.account.resolve_enums:
|
|
65
51
|
self.resolve_enums(endpoints, [(Control, "control")])
|
|
@@ -69,57 +55,38 @@ class DetectController(HttpController):
|
|
|
69
55
|
def describe_activity(self, filters: dict, view: str = "protected"):
|
|
70
56
|
"""Get report for an Account"""
|
|
71
57
|
params = dict(view=view, **filters)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
headers=self.account.headers,
|
|
75
|
-
params=params,
|
|
76
|
-
timeout=10,
|
|
77
|
-
)
|
|
58
|
+
|
|
59
|
+
res = self.get(f"{self.account.hq}/detect/activity", params=params)
|
|
78
60
|
return res.json()
|
|
79
61
|
|
|
80
62
|
@verify_credentials
|
|
81
63
|
def threat_hunt_activity(self, threat_hunt_id=None, test_id=None, threat_id=None):
|
|
82
64
|
"""Get threat hunt activity"""
|
|
83
|
-
|
|
65
|
+
params = dict(
|
|
84
66
|
threat_hunt_id=threat_hunt_id, test_id=test_id, threat_id=threat_id
|
|
85
67
|
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
headers=self.account.headers,
|
|
89
|
-
params=filters,
|
|
90
|
-
timeout=10,
|
|
91
|
-
)
|
|
68
|
+
|
|
69
|
+
res = self.get(f"{self.account.hq}/detect/threat_hunt_activity", params=params)
|
|
92
70
|
return res.json()
|
|
93
71
|
|
|
94
72
|
@verify_credentials
|
|
95
73
|
def list_tests(self, filters: dict = None):
|
|
96
74
|
"""List all tests available to an account"""
|
|
97
75
|
res = self.get(
|
|
98
|
-
f"{self.account.hq}/detect/tests",
|
|
99
|
-
headers=self.account.headers,
|
|
100
|
-
params=filters if filters else {},
|
|
101
|
-
timeout=10,
|
|
76
|
+
f"{self.account.hq}/detect/tests", params=filters if filters else {}
|
|
102
77
|
)
|
|
103
78
|
return res.json()
|
|
104
79
|
|
|
105
80
|
@verify_credentials
|
|
106
81
|
def get_test(self, test_id):
|
|
107
82
|
"""Get properties of an existing test"""
|
|
108
|
-
res = self.get(
|
|
109
|
-
f"{self.account.hq}/detect/tests/{test_id}",
|
|
110
|
-
headers=self.account.headers,
|
|
111
|
-
timeout=10,
|
|
112
|
-
)
|
|
83
|
+
res = self.get(f"{self.account.hq}/detect/tests/{test_id}")
|
|
113
84
|
return res.json()
|
|
114
85
|
|
|
115
86
|
@verify_credentials
|
|
116
87
|
def list_techniques(self):
|
|
117
88
|
"""List techniques"""
|
|
118
|
-
res = self.get(
|
|
119
|
-
f"{self.account.hq}/detect/techniques",
|
|
120
|
-
headers=self.account.headers,
|
|
121
|
-
timeout=10,
|
|
122
|
-
)
|
|
89
|
+
res = self.get(f"{self.account.hq}/detect/techniques")
|
|
123
90
|
return res.json()
|
|
124
91
|
|
|
125
92
|
@verify_credentials
|
|
@@ -127,51 +94,32 @@ class DetectController(HttpController):
|
|
|
127
94
|
"""List threats"""
|
|
128
95
|
res = self.get(
|
|
129
96
|
f"{self.account.hq}/detect/threats",
|
|
130
|
-
headers=self.account.headers,
|
|
131
|
-
params={},
|
|
132
|
-
timeout=10,
|
|
133
97
|
)
|
|
134
98
|
return res.json()
|
|
135
99
|
|
|
136
100
|
@verify_credentials
|
|
137
101
|
def get_threat(self, threat_id):
|
|
138
102
|
"""Get properties of an existing threat"""
|
|
139
|
-
res = self.get(
|
|
140
|
-
f"{self.account.hq}/detect/threats/{threat_id}",
|
|
141
|
-
headers=self.account.headers,
|
|
142
|
-
timeout=10,
|
|
143
|
-
)
|
|
103
|
+
res = self.get(f"{self.account.hq}/detect/threats/{threat_id}")
|
|
144
104
|
return res.json()
|
|
145
105
|
|
|
146
106
|
@verify_credentials
|
|
147
107
|
def list_detections(self):
|
|
148
108
|
"""List detections"""
|
|
149
|
-
res = self.get(
|
|
150
|
-
f"{self.account.hq}/detect/detections",
|
|
151
|
-
headers=self.account.headers,
|
|
152
|
-
params={},
|
|
153
|
-
timeout=10,
|
|
154
|
-
)
|
|
109
|
+
res = self.get(f"{self.account.hq}/detect/detections")
|
|
155
110
|
return res.json()
|
|
156
111
|
|
|
157
112
|
@verify_credentials
|
|
158
113
|
def get_detection(self, detection_id):
|
|
159
114
|
"""Get properties of an existing detection"""
|
|
160
|
-
res = self.get(
|
|
161
|
-
f"{self.account.hq}/detect/detections/{detection_id}",
|
|
162
|
-
headers=self.account.headers,
|
|
163
|
-
timeout=10,
|
|
164
|
-
)
|
|
115
|
+
res = self.get(f"{self.account.hq}/detect/detections/{detection_id}")
|
|
165
116
|
return res.json()
|
|
166
117
|
|
|
167
118
|
@verify_credentials
|
|
168
119
|
def list_threat_hunts(self, filters: dict = None):
|
|
169
120
|
"""List threat hunts"""
|
|
170
121
|
res = self.get(
|
|
171
|
-
f"{self.account.hq}/detect/threat_hunts",
|
|
172
|
-
headers=self.account.headers,
|
|
173
|
-
params=filters if filters else {},
|
|
174
|
-
timeout=10,
|
|
122
|
+
f"{self.account.hq}/detect/threat_hunts", params=filters if filters else {}
|
|
175
123
|
)
|
|
176
124
|
threat_hunts = res.json()
|
|
177
125
|
if self.account.resolve_enums:
|
|
@@ -181,11 +129,7 @@ class DetectController(HttpController):
|
|
|
181
129
|
@verify_credentials
|
|
182
130
|
def get_threat_hunt(self, threat_hunt_id):
|
|
183
131
|
"""Get properties of an existing threat hunt"""
|
|
184
|
-
res = self.get(
|
|
185
|
-
f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}",
|
|
186
|
-
headers=self.account.headers,
|
|
187
|
-
timeout=10,
|
|
188
|
-
)
|
|
132
|
+
res = self.get(f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}")
|
|
189
133
|
threat_hunt = res.json()
|
|
190
134
|
if self.account.resolve_enums:
|
|
191
135
|
self.resolve_enums(threat_hunt, [(Control, "control")])
|
|
@@ -195,35 +139,27 @@ class DetectController(HttpController):
|
|
|
195
139
|
def do_threat_hunt(self, threat_hunt_id):
|
|
196
140
|
"""Run a threat hunt"""
|
|
197
141
|
res = self.post(
|
|
198
|
-
f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}",
|
|
199
|
-
headers=self.account.headers,
|
|
200
|
-
timeout=30,
|
|
142
|
+
f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}", timeout=30
|
|
201
143
|
)
|
|
202
144
|
return res.json()
|
|
203
145
|
|
|
204
146
|
@verify_credentials
|
|
205
147
|
def download(self, test_id, filename):
|
|
206
148
|
"""Clone a test file or attachment"""
|
|
207
|
-
res = self.get(
|
|
208
|
-
f"{self.account.hq}/detect/tests/{test_id}/{filename}",
|
|
209
|
-
headers=self.account.headers,
|
|
210
|
-
timeout=10,
|
|
211
|
-
)
|
|
149
|
+
res = self.get(f"{self.account.hq}/detect/tests/{test_id}/{filename}")
|
|
212
150
|
return res.content
|
|
213
151
|
|
|
214
152
|
@verify_credentials
|
|
215
153
|
def schedule(self, items: list):
|
|
216
|
-
"""
|
|
154
|
+
"""
|
|
155
|
+
Schedule tests and threats so endpoints will start running them
|
|
217
156
|
|
|
218
157
|
Example: items=[dict(run_code='DAILY', tags='grp-1,grp2', test_id='123-123-123'),
|
|
219
158
|
dict(run_code='DAILY', tags='grp-1', threat_id='abc-def-ghi')]
|
|
220
159
|
"""
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
json=dict(items=items),
|
|
225
|
-
timeout=10,
|
|
226
|
-
)
|
|
160
|
+
body = dict(items=items)
|
|
161
|
+
|
|
162
|
+
res = self.post(url=f"{self.account.hq}/detect/queue", json=body)
|
|
227
163
|
schedule = res.json()
|
|
228
164
|
if self.account.resolve_enums:
|
|
229
165
|
self.resolve_enums(schedule, [(RunCode, "run_code")])
|
|
@@ -231,26 +167,21 @@ class DetectController(HttpController):
|
|
|
231
167
|
|
|
232
168
|
@verify_credentials
|
|
233
169
|
def unschedule(self, items: list):
|
|
234
|
-
"""
|
|
170
|
+
"""
|
|
171
|
+
Unschedule tests and threats so endpoints will stop running them
|
|
235
172
|
|
|
236
173
|
Example: items=[dict(tags='grp-1,grp2', test_id='123-123-123'),
|
|
237
174
|
dict(tags='grp-1', threat_id='abc-def-ghi')]
|
|
238
175
|
"""
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
json=dict(items=items),
|
|
243
|
-
timeout=10,
|
|
244
|
-
)
|
|
176
|
+
body = dict(items=items)
|
|
177
|
+
|
|
178
|
+
res = self.delete(f"{self.account.hq}/detect/queue", json=body)
|
|
245
179
|
return res.json()
|
|
246
180
|
|
|
247
181
|
@verify_credentials
|
|
248
182
|
def accept_terms(self, name, version):
|
|
249
183
|
"""Accept terms and conditions"""
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
json=dict(name=name, version=version),
|
|
254
|
-
timeout=10,
|
|
255
|
-
)
|
|
184
|
+
body = dict(name=name, version=version)
|
|
185
|
+
|
|
186
|
+
res = self.post(f"{self.account.hq}/iam/terms", json=body)
|
|
256
187
|
return res.json()
|
|
@@ -17,15 +17,11 @@ class ExportController(HttpController):
|
|
|
17
17
|
top: int = None,
|
|
18
18
|
):
|
|
19
19
|
"""Download partner data as a CSV"""
|
|
20
|
-
|
|
20
|
+
body = {
|
|
21
21
|
"$filter": filter,
|
|
22
22
|
"$orderby": orderby,
|
|
23
23
|
"$top": top,
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
params=params,
|
|
28
|
-
headers=self.account.headers,
|
|
29
|
-
timeout=10,
|
|
30
|
-
)
|
|
25
|
+
|
|
26
|
+
res = self.post(f"{self.account.hq}/export/scm/{export_type.name}", json=body)
|
|
31
27
|
return res.json()
|
|
@@ -11,6 +11,7 @@ class GenerateController(HttpController):
|
|
|
11
11
|
def upload_threat_intel(self, file: str):
|
|
12
12
|
with open(file, "rb") as f:
|
|
13
13
|
body = f.read()
|
|
14
|
+
|
|
14
15
|
res = self.post(
|
|
15
16
|
f"{self.account.hq}/generate/threat-intel",
|
|
16
17
|
data=body,
|
|
@@ -21,19 +22,15 @@ class GenerateController(HttpController):
|
|
|
21
22
|
|
|
22
23
|
@verify_credentials
|
|
23
24
|
def get_threat_intel(self, job_id: str):
|
|
24
|
-
res = self.get(
|
|
25
|
-
f"{self.account.hq}/generate/threat-intel/{job_id}",
|
|
26
|
-
headers=self.account.headers,
|
|
27
|
-
timeout=10,
|
|
28
|
-
)
|
|
25
|
+
res = self.get(f"{self.account.hq}/generate/threat-intel/{job_id}")
|
|
29
26
|
return res.json()
|
|
30
27
|
|
|
31
28
|
@verify_credentials
|
|
32
29
|
def generate_from_partner_advisory(self, partner: Control, advisory_id: str):
|
|
33
30
|
params = dict(advisory_id=advisory_id)
|
|
31
|
+
|
|
34
32
|
res = self.post(
|
|
35
33
|
f"{self.account.hq}/generate/partner-advisories/{partner.name}",
|
|
36
|
-
headers=self.account.headers,
|
|
37
34
|
json=params,
|
|
38
35
|
timeout=30,
|
|
39
36
|
)
|