prelude-sdk 2.6.38__tar.gz → 2.6.40__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.38 → prelude_sdk-2.6.40}/PKG-INFO +1 -1
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/build_controller.py +16 -84
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/detect_controller.py +33 -102
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/export_controller.py +3 -7
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/generate_controller.py +3 -6
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/http_controller.py +28 -12
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/iam_controller.py +20 -99
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/jobs_controller.py +2 -8
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/partner_controller.py +13 -30
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/probe_controller.py +1 -3
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/scm_controller.py +69 -183
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/models/codes.py +1 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk.egg-info/PKG-INFO +1 -1
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/setup.cfg +1 -1
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_scm.py +13 -18
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_scm_build.py +5 -3
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/LICENSE +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/README.md +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/__init__.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/controllers/__init__.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/models/__init__.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk/models/account.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk.egg-info/SOURCES.txt +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk.egg-info/dependency_links.txt +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk.egg-info/requires.txt +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/prelude_sdk.egg-info/top_level.txt +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/pyproject.toml +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_build.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_detect.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_generate.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_iam.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_partner.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/test_probe.py +0 -0
- {prelude_sdk-2.6.38 → prelude_sdk-2.6.40}/tests/testutils.py +0 -0
|
@@ -14,10 +14,7 @@ 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
|
|
|
@@ -30,12 +27,7 @@ class BuildController(HttpController):
|
|
|
30
27
|
if test_id:
|
|
31
28
|
body["id"] = test_id
|
|
32
29
|
|
|
33
|
-
res = self.post(
|
|
34
|
-
f"{self.account.hq}/build/tests",
|
|
35
|
-
json=body,
|
|
36
|
-
headers=self.account.headers,
|
|
37
|
-
timeout=10,
|
|
38
|
-
)
|
|
30
|
+
res = self.post(f"{self.account.hq}/build/tests", json=body)
|
|
39
31
|
return res.json()
|
|
40
32
|
|
|
41
33
|
@verify_credentials
|
|
@@ -58,33 +50,21 @@ class BuildController(HttpController):
|
|
|
58
50
|
if technique is not None:
|
|
59
51
|
body["technique"] = technique
|
|
60
52
|
|
|
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
|
-
)
|
|
53
|
+
res = self.post(f"{self.account.hq}/build/tests/{test_id}", json=body)
|
|
67
54
|
return res.json()
|
|
68
55
|
|
|
69
56
|
@verify_credentials
|
|
70
57
|
def delete_test(self, test_id, purge):
|
|
71
58
|
"""Delete an existing test"""
|
|
72
59
|
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,
|
|
60
|
+
f"{self.account.hq}/build/tests/{test_id}", json=dict(purge=purge)
|
|
77
61
|
)
|
|
78
62
|
return res.json()
|
|
79
63
|
|
|
80
64
|
@verify_credentials
|
|
81
65
|
def undelete_test(self, test_id):
|
|
82
66
|
"""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
|
-
)
|
|
67
|
+
res = self.post(f"{self.account.hq}/build/tests/{test_id}/undelete")
|
|
88
68
|
return res.json()
|
|
89
69
|
|
|
90
70
|
@verify_credentials
|
|
@@ -97,11 +77,11 @@ class BuildController(HttpController):
|
|
|
97
77
|
query_params = ""
|
|
98
78
|
if skip_compile:
|
|
99
79
|
query_params = "?" + urllib.parse.urlencode(dict(skip_compile=True))
|
|
80
|
+
|
|
100
81
|
res = self.post(
|
|
101
82
|
f"{self.account.hq}/build/tests/{test_id}/{filename}{query_params}",
|
|
102
83
|
data=data,
|
|
103
84
|
headers=h,
|
|
104
|
-
timeout=10,
|
|
105
85
|
)
|
|
106
86
|
return res.json()
|
|
107
87
|
|
|
@@ -111,18 +91,12 @@ class BuildController(HttpController):
|
|
|
111
91
|
res = self.post(
|
|
112
92
|
f"{self.account.hq}/build/compile",
|
|
113
93
|
json=dict(code=code, source_test_id=source_test_id),
|
|
114
|
-
headers=self.account.headers,
|
|
115
|
-
timeout=10,
|
|
116
94
|
)
|
|
117
95
|
return res.json()
|
|
118
96
|
|
|
119
97
|
@verify_credentials
|
|
120
98
|
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
|
-
)
|
|
99
|
+
res = self.get(f"{self.account.hq}/build/compile/{job_id}")
|
|
126
100
|
return res.json()
|
|
127
101
|
|
|
128
102
|
@verify_credentials
|
|
@@ -140,12 +114,7 @@ class BuildController(HttpController):
|
|
|
140
114
|
if tests:
|
|
141
115
|
body["tests"] = tests
|
|
142
116
|
|
|
143
|
-
res = self.post(
|
|
144
|
-
f"{self.account.hq}/build/threats",
|
|
145
|
-
json=body,
|
|
146
|
-
headers=self.account.headers,
|
|
147
|
-
timeout=10,
|
|
148
|
-
)
|
|
117
|
+
res = self.post(f"{self.account.hq}/build/threats", json=body)
|
|
149
118
|
return res.json()
|
|
150
119
|
|
|
151
120
|
@verify_credentials
|
|
@@ -171,12 +140,7 @@ class BuildController(HttpController):
|
|
|
171
140
|
if tests is not None:
|
|
172
141
|
body["tests"] = tests
|
|
173
142
|
|
|
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
|
-
)
|
|
143
|
+
res = self.post(f"{self.account.hq}/build/threats/{threat_id}", json=body)
|
|
180
144
|
return res.json()
|
|
181
145
|
|
|
182
146
|
@verify_credentials
|
|
@@ -185,19 +149,13 @@ class BuildController(HttpController):
|
|
|
185
149
|
res = self.delete(
|
|
186
150
|
f"{self.account.hq}/build/threats/{threat_id}",
|
|
187
151
|
json=dict(purge=purge),
|
|
188
|
-
headers=self.account.headers,
|
|
189
|
-
timeout=10,
|
|
190
152
|
)
|
|
191
153
|
return res.json()
|
|
192
154
|
|
|
193
155
|
@verify_credentials
|
|
194
156
|
def undelete_threat(self, threat_id):
|
|
195
157
|
"""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
|
-
)
|
|
158
|
+
res = self.post(f"{self.account.hq}/build/threats/{threat_id}/undelete")
|
|
201
159
|
return res.json()
|
|
202
160
|
|
|
203
161
|
@verify_credentials
|
|
@@ -211,12 +169,7 @@ class BuildController(HttpController):
|
|
|
211
169
|
if rule_id:
|
|
212
170
|
body["rule_id"] = rule_id
|
|
213
171
|
|
|
214
|
-
res = self.post(
|
|
215
|
-
f"{self.account.hq}/build/detections",
|
|
216
|
-
json=body,
|
|
217
|
-
headers=self.account.headers,
|
|
218
|
-
timeout=10,
|
|
219
|
-
)
|
|
172
|
+
res = self.post(f"{self.account.hq}/build/detections", json=body)
|
|
220
173
|
return res.json()
|
|
221
174
|
|
|
222
175
|
@verify_credentials
|
|
@@ -228,22 +181,13 @@ class BuildController(HttpController):
|
|
|
228
181
|
if test_id:
|
|
229
182
|
body["test_id"] = test_id
|
|
230
183
|
|
|
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
|
-
)
|
|
184
|
+
res = self.post(f"{self.account.hq}/build/detections/{detection_id}", json=body)
|
|
237
185
|
return res.json()
|
|
238
186
|
|
|
239
187
|
@verify_credentials
|
|
240
188
|
def delete_detection(self, detection_id: str):
|
|
241
189
|
"""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
|
-
)
|
|
190
|
+
res = self.delete(f"{self.account.hq}/build/detections/{detection_id}")
|
|
247
191
|
return res.json()
|
|
248
192
|
|
|
249
193
|
@verify_credentials
|
|
@@ -265,12 +209,7 @@ class BuildController(HttpController):
|
|
|
265
209
|
if threat_hunt_id:
|
|
266
210
|
body["id"] = threat_hunt_id
|
|
267
211
|
|
|
268
|
-
res = self.post(
|
|
269
|
-
f"{self.account.hq}/build/threat_hunts",
|
|
270
|
-
json=body,
|
|
271
|
-
headers=self.account.headers,
|
|
272
|
-
timeout=10,
|
|
273
|
-
)
|
|
212
|
+
res = self.post(f"{self.account.hq}/build/threat_hunts", json=body)
|
|
274
213
|
threat_hunt = res.json()
|
|
275
214
|
if self.account.resolve_enums:
|
|
276
215
|
self.resolve_enums(threat_hunt, [(Control, "control")])
|
|
@@ -294,10 +233,7 @@ class BuildController(HttpController):
|
|
|
294
233
|
body["test_id"] = test_id
|
|
295
234
|
|
|
296
235
|
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,
|
|
236
|
+
f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}", json=body
|
|
301
237
|
)
|
|
302
238
|
threat_hunt = res.json()
|
|
303
239
|
if self.account.resolve_enums:
|
|
@@ -307,9 +243,5 @@ class BuildController(HttpController):
|
|
|
307
243
|
@verify_credentials
|
|
308
244
|
def delete_threat_hunt(self, threat_hunt_id: str):
|
|
309
245
|
"""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
|
-
)
|
|
246
|
+
res = self.delete(f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}")
|
|
315
247
|
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
|
)
|
|
@@ -42,42 +42,58 @@ class HttpController(object):
|
|
|
42
42
|
elif isinstance(v, dict) or isinstance(v, list):
|
|
43
43
|
self._resolve_enum(v, enum_class, key)
|
|
44
44
|
|
|
45
|
-
def get(self, url, retry=True, **kwargs):
|
|
46
|
-
res = self._session.get(
|
|
45
|
+
def get(self, url, retry=True, timeout=10, headers=None, **kwargs):
|
|
46
|
+
res = self._session.get(
|
|
47
|
+
url, timeout=timeout, headers=headers or self.account.headers, **kwargs
|
|
48
|
+
)
|
|
47
49
|
if res.status_code == 200:
|
|
48
50
|
return res
|
|
49
51
|
if res.status_code == 401 and retry and self.account.token_location:
|
|
50
52
|
self.account.refresh_tokens()
|
|
51
53
|
self.account.update_auth_header()
|
|
52
|
-
return self.get(
|
|
54
|
+
return self.get(
|
|
55
|
+
url, retry=False, timeout=timeout, headers=headers, **kwargs
|
|
56
|
+
)
|
|
53
57
|
raise Exception(res.text)
|
|
54
58
|
|
|
55
|
-
def post(self, url, retry=True, **kwargs):
|
|
56
|
-
res = self._session.post(
|
|
59
|
+
def post(self, url, retry=True, timeout=10, headers=None, **kwargs):
|
|
60
|
+
res = self._session.post(
|
|
61
|
+
url, timeout=timeout, headers=headers or self.account.headers, **kwargs
|
|
62
|
+
)
|
|
57
63
|
if res.status_code == 200:
|
|
58
64
|
return res
|
|
59
65
|
if res.status_code == 401 and retry and self.account.token_location:
|
|
60
66
|
self.account.refresh_tokens()
|
|
61
67
|
self.account.update_auth_header()
|
|
62
|
-
return self.post(
|
|
68
|
+
return self.post(
|
|
69
|
+
url, retry=False, timeout=timeout, headers=headers, **kwargs
|
|
70
|
+
)
|
|
63
71
|
raise Exception(res.text)
|
|
64
72
|
|
|
65
|
-
def delete(self, url, retry=True, **kwargs):
|
|
66
|
-
res = self._session.delete(
|
|
73
|
+
def delete(self, url, retry=True, timeout=10, headers=None, **kwargs):
|
|
74
|
+
res = self._session.delete(
|
|
75
|
+
url, timeout=timeout, headers=headers or self.account.headers, **kwargs
|
|
76
|
+
)
|
|
67
77
|
if res.status_code == 200:
|
|
68
78
|
return res
|
|
69
79
|
if res.status_code == 401 and retry and self.account.token_location:
|
|
70
80
|
self.account.refresh_tokens()
|
|
71
81
|
self.account.update_auth_header()
|
|
72
|
-
return self.delete(
|
|
82
|
+
return self.delete(
|
|
83
|
+
url, retry=False, timeout=timeout, headers=headers, **kwargs
|
|
84
|
+
)
|
|
73
85
|
raise Exception(res.text)
|
|
74
86
|
|
|
75
|
-
def put(self, url, retry=True, **kwargs):
|
|
76
|
-
res = self._session.put(
|
|
87
|
+
def put(self, url, retry=True, timeout=10, headers=None, **kwargs):
|
|
88
|
+
res = self._session.put(
|
|
89
|
+
url, timeout=timeout, headers=headers or self.account.headers, **kwargs
|
|
90
|
+
)
|
|
77
91
|
if res.status_code == 200:
|
|
78
92
|
return res
|
|
79
93
|
if res.status_code == 401 and retry and self.account.token_location:
|
|
80
94
|
self.account.refresh_tokens()
|
|
81
95
|
self.account.update_auth_header()
|
|
82
|
-
return self.put(
|
|
96
|
+
return self.put(
|
|
97
|
+
url, retry=False, timeout=timeout, headers=headers, **kwargs
|
|
98
|
+
)
|
|
83
99
|
raise Exception(res.text)
|