prelude-cli-beta 1399__py3-none-any.whl → 1404__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-1404.dist-info/METADATA +46 -0
- prelude_cli_beta-1404.dist-info/RECORD +20 -0
- prelude_cli_beta-1404.dist-info/top_level.txt +1 -0
- prelude_sdk_beta/controllers/build_controller.py +309 -0
- prelude_sdk_beta/controllers/detect_controller.py +243 -0
- prelude_sdk_beta/controllers/export_controller.py +31 -0
- prelude_sdk_beta/controllers/generate_controller.py +40 -0
- prelude_sdk_beta/controllers/http_controller.py +63 -0
- prelude_sdk_beta/controllers/iam_controller.py +278 -0
- prelude_sdk_beta/controllers/jobs_controller.py +26 -0
- prelude_sdk_beta/controllers/partner_controller.py +166 -0
- prelude_sdk_beta/controllers/probe_controller.py +14 -0
- prelude_sdk_beta/controllers/scm_controller.py +424 -0
- prelude_sdk_beta/models/account.py +264 -0
- prelude_sdk_beta/models/codes.py +446 -0
- prelude_cli/cli.py +0 -47
- prelude_cli/templates/README.md +0 -28
- prelude_cli/templates/template.go +0 -24
- prelude_cli/views/auth.py +0 -56
- prelude_cli/views/build.py +0 -488
- prelude_cli/views/configure.py +0 -29
- prelude_cli/views/detect.py +0 -438
- prelude_cli/views/generate.py +0 -125
- prelude_cli/views/iam.py +0 -368
- prelude_cli/views/jobs.py +0 -50
- prelude_cli/views/partner.py +0 -192
- prelude_cli/views/scm.py +0 -471
- prelude_cli/views/shared.py +0 -37
- prelude_cli_beta-1399.dist-info/METADATA +0 -38
- prelude_cli_beta-1399.dist-info/RECORD +0 -22
- prelude_cli_beta-1399.dist-info/entry_points.txt +0 -3
- prelude_cli_beta-1399.dist-info/top_level.txt +0 -1
- {prelude_cli_beta-1399.dist-info → prelude_cli_beta-1404.dist-info}/WHEEL +0 -0
- {prelude_cli_beta-1399.dist-info → prelude_cli_beta-1404.dist-info}/licenses/LICENSE +0 -0
- {prelude_cli → prelude_sdk_beta}/__init__.py +0 -0
- {prelude_cli/templates → prelude_sdk_beta/controllers}/__init__.py +0 -0
- {prelude_cli/views → prelude_sdk_beta/models}/__init__.py +0 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from enum import Enum, EnumMeta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MissingItem(EnumMeta):
|
|
7
|
+
def __getitem__(cls, name):
|
|
8
|
+
try:
|
|
9
|
+
return super().__getitem__(name.upper())
|
|
10
|
+
except (AttributeError, KeyError):
|
|
11
|
+
try:
|
|
12
|
+
return cls(int(name))
|
|
13
|
+
except ValueError:
|
|
14
|
+
return cls(name)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RunCode(Enum, metaclass=MissingItem):
|
|
18
|
+
INVALID = -1
|
|
19
|
+
DAILY = 1
|
|
20
|
+
WEEKLY = 2
|
|
21
|
+
MONTHLY = 3
|
|
22
|
+
SMART = 4
|
|
23
|
+
DEBUG = 5
|
|
24
|
+
RUN_ONCE = 6
|
|
25
|
+
MONDAY = 10
|
|
26
|
+
TUESDAY = 11
|
|
27
|
+
WEDNESDAY = 12
|
|
28
|
+
THURSDAY = 13
|
|
29
|
+
FRIDAY = 14
|
|
30
|
+
SATURDAY = 15
|
|
31
|
+
SUNDAY = 16
|
|
32
|
+
MONTH_1 = 20
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def _missing_(cls, value):
|
|
36
|
+
return RunCode.DAILY
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Mode(Enum, metaclass=MissingItem):
|
|
40
|
+
MANUAL = 0
|
|
41
|
+
FROZEN = 1
|
|
42
|
+
AUTOPILOT = 2
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def _missing_(cls, value):
|
|
46
|
+
return Mode.MANUAL
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Permission(Enum, metaclass=MissingItem):
|
|
50
|
+
INVALID = -1
|
|
51
|
+
ADMIN = 0
|
|
52
|
+
EXECUTIVE = 1
|
|
53
|
+
BUILD = 2
|
|
54
|
+
SERVICE = 3
|
|
55
|
+
SUPPORT = 5
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def _missing_(cls, value):
|
|
59
|
+
return Permission.INVALID
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ExitCode(Enum):
|
|
63
|
+
MISSING = -1
|
|
64
|
+
UNKNOWN_ERROR = 1
|
|
65
|
+
MALFORMED_TEST = 2
|
|
66
|
+
UNREPORTED = 3
|
|
67
|
+
PROCESS_BLOCKED = 9
|
|
68
|
+
PROCESS_BLOCKED_GRACEFULLY = 15
|
|
69
|
+
PROTECTED = 100
|
|
70
|
+
UNPROTECTED = 101
|
|
71
|
+
TIMED_OUT = 102
|
|
72
|
+
FAILED_CLEANUP = 103
|
|
73
|
+
TEST_NOT_RELEVANT = 104
|
|
74
|
+
DYNAMIC_QUARANTINE = 105
|
|
75
|
+
BLOCKED_AT_PERIMETER = 106
|
|
76
|
+
EXPLOIT_PREVENTED = 107
|
|
77
|
+
ENDPOINT_NOT_RELEVANT = 108
|
|
78
|
+
INSUFFICIENT_PRIVILEGES = 109
|
|
79
|
+
INCORRECTLY_BLOCKED = 110
|
|
80
|
+
PREVENTED_EXECUTION = 126
|
|
81
|
+
STATIC_QUARANTINE = 127
|
|
82
|
+
BLOCKED = 137
|
|
83
|
+
UNEXPECTED_ERROR = 256
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
def _missing_(cls, value):
|
|
87
|
+
if value and not isinstance(value, int):
|
|
88
|
+
return cls(int(value))
|
|
89
|
+
logging.warning("Unknown ExitCode: %s", str(value))
|
|
90
|
+
return ExitCode.MISSING
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def state(self):
|
|
94
|
+
for k, v in State.mapping().items():
|
|
95
|
+
if self in v:
|
|
96
|
+
return k
|
|
97
|
+
return State.NONE
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class State(Enum):
|
|
101
|
+
NONE = 0
|
|
102
|
+
PROTECTED = 1
|
|
103
|
+
UNPROTECTED = 2
|
|
104
|
+
ERROR = 3
|
|
105
|
+
NOT_RELEVANT = 4
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def mapping(cls):
|
|
109
|
+
return {
|
|
110
|
+
State.ERROR: [
|
|
111
|
+
ExitCode.FAILED_CLEANUP,
|
|
112
|
+
ExitCode.INCORRECTLY_BLOCKED,
|
|
113
|
+
ExitCode.MALFORMED_TEST,
|
|
114
|
+
ExitCode.TIMED_OUT,
|
|
115
|
+
ExitCode.UNEXPECTED_ERROR,
|
|
116
|
+
ExitCode.UNKNOWN_ERROR,
|
|
117
|
+
ExitCode.UNREPORTED,
|
|
118
|
+
],
|
|
119
|
+
State.NONE: [ExitCode.MISSING],
|
|
120
|
+
State.NOT_RELEVANT: [
|
|
121
|
+
ExitCode.ENDPOINT_NOT_RELEVANT,
|
|
122
|
+
ExitCode.INSUFFICIENT_PRIVILEGES,
|
|
123
|
+
ExitCode.TEST_NOT_RELEVANT,
|
|
124
|
+
],
|
|
125
|
+
State.PROTECTED: [
|
|
126
|
+
ExitCode.BLOCKED,
|
|
127
|
+
ExitCode.BLOCKED_AT_PERIMETER,
|
|
128
|
+
ExitCode.DYNAMIC_QUARANTINE,
|
|
129
|
+
ExitCode.EXPLOIT_PREVENTED,
|
|
130
|
+
ExitCode.PREVENTED_EXECUTION,
|
|
131
|
+
ExitCode.PROCESS_BLOCKED,
|
|
132
|
+
ExitCode.PROCESS_BLOCKED_GRACEFULLY,
|
|
133
|
+
ExitCode.PROTECTED,
|
|
134
|
+
ExitCode.STATIC_QUARANTINE,
|
|
135
|
+
],
|
|
136
|
+
State.UNPROTECTED: [
|
|
137
|
+
ExitCode.UNPROTECTED,
|
|
138
|
+
],
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class DOS(Enum):
|
|
143
|
+
none = "none"
|
|
144
|
+
arm64 = "arm64"
|
|
145
|
+
x86_64 = "x86_64"
|
|
146
|
+
aarch64 = "arm64"
|
|
147
|
+
amd64 = "x86_64"
|
|
148
|
+
x86 = "x86_64"
|
|
149
|
+
|
|
150
|
+
@classmethod
|
|
151
|
+
def normalize(cls, dos: str):
|
|
152
|
+
try:
|
|
153
|
+
arch = dos.split("-", 1)[-1]
|
|
154
|
+
return dos[: -len(arch)].lower() + cls[arch.lower()].value
|
|
155
|
+
except (KeyError, IndexError, AttributeError):
|
|
156
|
+
return cls.none.value
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class Control(Enum, metaclass=MissingItem):
|
|
160
|
+
INVALID = -1
|
|
161
|
+
NONE = 0
|
|
162
|
+
CROWDSTRIKE = 1
|
|
163
|
+
DEFENDER = 2
|
|
164
|
+
SPLUNK = 3
|
|
165
|
+
SENTINELONE = 4
|
|
166
|
+
VECTR = 5
|
|
167
|
+
S3 = 6
|
|
168
|
+
INTUNE = 7
|
|
169
|
+
SERVICENOW = 8
|
|
170
|
+
OKTA = 9
|
|
171
|
+
M365 = 10
|
|
172
|
+
ENTRA = 11
|
|
173
|
+
JAMF = 12
|
|
174
|
+
CROWDSTRIKE_IDENTITY = 13
|
|
175
|
+
GMAIL = 14
|
|
176
|
+
GOOGLE_IDENTITY = 15
|
|
177
|
+
DEFENDER_DISCOVERY = 16
|
|
178
|
+
TENABLE = 17
|
|
179
|
+
EC2 = 18
|
|
180
|
+
AWS_SSM = 19
|
|
181
|
+
AZURE_VM = 20
|
|
182
|
+
GITHUB = 21
|
|
183
|
+
TENABLE_DISCOVERY = 22
|
|
184
|
+
QUALYS = 23
|
|
185
|
+
QUALYS_DISCOVERY = 24
|
|
186
|
+
|
|
187
|
+
@classmethod
|
|
188
|
+
def _missing_(cls, value):
|
|
189
|
+
return Control.INVALID
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def control_category(self):
|
|
193
|
+
for k, v in ControlCategory.mapping().items():
|
|
194
|
+
if self in v:
|
|
195
|
+
return k
|
|
196
|
+
return ControlCategory.NONE
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def scm_category(self):
|
|
200
|
+
for k, v in SCMCategory.control_mapping().items():
|
|
201
|
+
if self in v:
|
|
202
|
+
return k
|
|
203
|
+
return SCMCategory.NONE
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class ControlCategory(Enum, metaclass=MissingItem):
|
|
207
|
+
INVALID = -1
|
|
208
|
+
NONE = 0
|
|
209
|
+
CLOUD = 1
|
|
210
|
+
EMAIL = 2
|
|
211
|
+
IDENTITY = 3
|
|
212
|
+
NETWORK = 4
|
|
213
|
+
XDR = 5
|
|
214
|
+
ASSET_MANAGER = 6
|
|
215
|
+
DISCOVERED_DEVICES = 7
|
|
216
|
+
VULN_MANAGER = 8
|
|
217
|
+
SIEM = 9
|
|
218
|
+
PRIVATE_REPO = 10
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def _missing_(cls, value):
|
|
222
|
+
return ControlCategory.INVALID
|
|
223
|
+
|
|
224
|
+
@classmethod
|
|
225
|
+
def mapping(cls):
|
|
226
|
+
return {
|
|
227
|
+
ControlCategory.ASSET_MANAGER: [
|
|
228
|
+
Control.AWS_SSM,
|
|
229
|
+
Control.INTUNE,
|
|
230
|
+
Control.JAMF,
|
|
231
|
+
],
|
|
232
|
+
ControlCategory.CLOUD: [],
|
|
233
|
+
ControlCategory.DISCOVERED_DEVICES: [
|
|
234
|
+
Control.AZURE_VM,
|
|
235
|
+
Control.DEFENDER_DISCOVERY,
|
|
236
|
+
Control.EC2,
|
|
237
|
+
Control.QUALYS_DISCOVERY,
|
|
238
|
+
Control.SERVICENOW,
|
|
239
|
+
Control.TENABLE_DISCOVERY,
|
|
240
|
+
],
|
|
241
|
+
ControlCategory.EMAIL: [
|
|
242
|
+
Control.GMAIL,
|
|
243
|
+
Control.M365,
|
|
244
|
+
],
|
|
245
|
+
ControlCategory.IDENTITY: [
|
|
246
|
+
Control.CROWDSTRIKE_IDENTITY,
|
|
247
|
+
Control.ENTRA,
|
|
248
|
+
Control.GOOGLE_IDENTITY,
|
|
249
|
+
Control.OKTA,
|
|
250
|
+
],
|
|
251
|
+
ControlCategory.NETWORK: [],
|
|
252
|
+
ControlCategory.PRIVATE_REPO: [
|
|
253
|
+
Control.GITHUB,
|
|
254
|
+
],
|
|
255
|
+
ControlCategory.SIEM: [
|
|
256
|
+
Control.S3,
|
|
257
|
+
Control.SPLUNK,
|
|
258
|
+
Control.VECTR,
|
|
259
|
+
],
|
|
260
|
+
ControlCategory.VULN_MANAGER: [Control.QUALYS, Control.TENABLE],
|
|
261
|
+
ControlCategory.XDR: [
|
|
262
|
+
Control.CROWDSTRIKE,
|
|
263
|
+
Control.DEFENDER,
|
|
264
|
+
Control.SENTINELONE,
|
|
265
|
+
],
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class SCMCategory(Enum, metaclass=MissingItem):
|
|
270
|
+
INVALID = -1
|
|
271
|
+
NONE = 0
|
|
272
|
+
ENDPOINT = 1
|
|
273
|
+
INBOX = 2
|
|
274
|
+
USER = 3
|
|
275
|
+
|
|
276
|
+
@classmethod
|
|
277
|
+
def _missing_(cls, value):
|
|
278
|
+
return SCMCategory.INVALID
|
|
279
|
+
|
|
280
|
+
@classmethod
|
|
281
|
+
def control_mapping(cls):
|
|
282
|
+
return {
|
|
283
|
+
SCMCategory.ENDPOINT: [
|
|
284
|
+
Control.AWS_SSM,
|
|
285
|
+
Control.AZURE_VM,
|
|
286
|
+
Control.CROWDSTRIKE,
|
|
287
|
+
Control.DEFENDER,
|
|
288
|
+
Control.DEFENDER_DISCOVERY,
|
|
289
|
+
Control.EC2,
|
|
290
|
+
Control.INTUNE,
|
|
291
|
+
Control.JAMF,
|
|
292
|
+
Control.QUALYS,
|
|
293
|
+
Control.QUALYS_DISCOVERY,
|
|
294
|
+
Control.SENTINELONE,
|
|
295
|
+
Control.SERVICENOW,
|
|
296
|
+
Control.TENABLE,
|
|
297
|
+
Control.TENABLE_DISCOVERY,
|
|
298
|
+
],
|
|
299
|
+
SCMCategory.USER: [
|
|
300
|
+
Control.CROWDSTRIKE_IDENTITY,
|
|
301
|
+
Control.ENTRA,
|
|
302
|
+
Control.GOOGLE_IDENTITY,
|
|
303
|
+
Control.OKTA,
|
|
304
|
+
],
|
|
305
|
+
SCMCategory.INBOX: [
|
|
306
|
+
Control.GMAIL,
|
|
307
|
+
Control.M365,
|
|
308
|
+
],
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
@classmethod
|
|
312
|
+
def category_mapping(cls):
|
|
313
|
+
return {
|
|
314
|
+
SCMCategory.ENDPOINT: [
|
|
315
|
+
ControlCategory.ASSET_MANAGER,
|
|
316
|
+
ControlCategory.DISCOVERED_DEVICES,
|
|
317
|
+
ControlCategory.VULN_MANAGER,
|
|
318
|
+
ControlCategory.XDR,
|
|
319
|
+
],
|
|
320
|
+
SCMCategory.USER: [ControlCategory.IDENTITY],
|
|
321
|
+
SCMCategory.INBOX: [ControlCategory.EMAIL],
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class BackgroundJobTypes(Enum, metaclass=MissingItem):
|
|
326
|
+
INVALID = -1
|
|
327
|
+
UPDATE_SCM = 1
|
|
328
|
+
DEPLOY_PROBE = 2
|
|
329
|
+
OBSERVED_DETECTED = 3
|
|
330
|
+
PRELUDE_ENDPOINT_SYNC = 4
|
|
331
|
+
EXPORT_SCM = 5
|
|
332
|
+
PARTNER_GROUPS = 6
|
|
333
|
+
|
|
334
|
+
@classmethod
|
|
335
|
+
def _missing_(cls, value):
|
|
336
|
+
return BackgroundJobTypes.INVALID
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class EDRResponse(Enum, metaclass=MissingItem):
|
|
340
|
+
INVALID = -1
|
|
341
|
+
OBSERVE = 1
|
|
342
|
+
DETECT = 2
|
|
343
|
+
PREVENT = 3
|
|
344
|
+
|
|
345
|
+
@classmethod
|
|
346
|
+
def _missing_(cls, value):
|
|
347
|
+
return EDRResponse.INVALID
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class PartnerEvents(Enum, metaclass=MissingItem):
|
|
351
|
+
INVALID = -1
|
|
352
|
+
REDUCED_FUNCTIONALITY_MODE = 1
|
|
353
|
+
NO_EDR = 2
|
|
354
|
+
MISSING_EDR_POLICY = 3
|
|
355
|
+
MISSING_AV_POLICY = 4
|
|
356
|
+
MISSING_MFA = 5
|
|
357
|
+
NO_ASSET_MANAGER = 6
|
|
358
|
+
MISCONFIGURED_POLICY_SETTING = 7
|
|
359
|
+
MISSING_SCAN = 8
|
|
360
|
+
OUT_OF_DATE_SCAN = 9
|
|
361
|
+
NO_VULN_MANAGER = 10
|
|
362
|
+
USER_MISSING_ASSET_MANAGER = 11
|
|
363
|
+
USER_MISSING_EDR = 12
|
|
364
|
+
USER_MISSING_VULN_MANAGER = 13
|
|
365
|
+
|
|
366
|
+
@classmethod
|
|
367
|
+
def _missing_(cls, value):
|
|
368
|
+
return PartnerEvents.INVALID
|
|
369
|
+
|
|
370
|
+
@classmethod
|
|
371
|
+
def control_category_mapping(cls):
|
|
372
|
+
return {
|
|
373
|
+
PartnerEvents.REDUCED_FUNCTIONALITY_MODE: [ControlCategory.XDR],
|
|
374
|
+
PartnerEvents.NO_EDR: [
|
|
375
|
+
ControlCategory.XDR,
|
|
376
|
+
],
|
|
377
|
+
PartnerEvents.MISSING_EDR_POLICY: [ControlCategory.XDR],
|
|
378
|
+
PartnerEvents.MISSING_AV_POLICY: [ControlCategory.XDR],
|
|
379
|
+
PartnerEvents.MISSING_MFA: [ControlCategory.IDENTITY],
|
|
380
|
+
PartnerEvents.NO_ASSET_MANAGER: [ControlCategory.ASSET_MANAGER],
|
|
381
|
+
PartnerEvents.MISCONFIGURED_POLICY_SETTING: [
|
|
382
|
+
ControlCategory.XDR,
|
|
383
|
+
ControlCategory.EMAIL,
|
|
384
|
+
ControlCategory.IDENTITY,
|
|
385
|
+
],
|
|
386
|
+
PartnerEvents.MISSING_SCAN: [ControlCategory.VULN_MANAGER],
|
|
387
|
+
PartnerEvents.OUT_OF_DATE_SCAN: [ControlCategory.VULN_MANAGER],
|
|
388
|
+
PartnerEvents.NO_VULN_MANAGER: [ControlCategory.VULN_MANAGER],
|
|
389
|
+
PartnerEvents.USER_MISSING_ASSET_MANAGER: [ControlCategory.IDENTITY],
|
|
390
|
+
PartnerEvents.USER_MISSING_EDR: [ControlCategory.IDENTITY],
|
|
391
|
+
PartnerEvents.USER_MISSING_VULN_MANAGER: [ControlCategory.IDENTITY],
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
class AlertTypes(Enum, metaclass=MissingItem):
|
|
396
|
+
INVALID = -1
|
|
397
|
+
NEW_REDUCED_FUNCTIONALITY_MODE_ENDPOINTS = 1
|
|
398
|
+
NEW_NO_EDR_ENDPOINTS = 2
|
|
399
|
+
NEW_MISSING_EDR_POLICY_ENDPOINTS = 3
|
|
400
|
+
NEW_MISSING_AV_POLICY_ENDPOINTS = 4
|
|
401
|
+
NEW_MISSING_MFA_USERS = 5
|
|
402
|
+
NEW_NO_ASSET_MANAGER_ENDPOINTS = 6
|
|
403
|
+
NEW_POLICY_SETTING_FAILURE = 7
|
|
404
|
+
NEW_POLICY_SETTING_PASS = 8
|
|
405
|
+
NEW_MISSING_SCAN_ENDPOINTS = 9
|
|
406
|
+
NEW_NO_VULN_MANAGER_ENDPOINTS = 10
|
|
407
|
+
NEW_OUT_OF_DATE_SCAN_ENDPOINTS = 11
|
|
408
|
+
NEW_USER_MISSING_ASSET_MANAGER = 12
|
|
409
|
+
NEW_USER_MISSING_EDR = 13
|
|
410
|
+
NEW_USER_MISSING_VULN_MANAGER = 14
|
|
411
|
+
|
|
412
|
+
@classmethod
|
|
413
|
+
def _missing_(cls, value):
|
|
414
|
+
return AlertTypes.INVALID
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
class PolicyType(Enum, metaclass=MissingItem):
|
|
418
|
+
INVALID = 0
|
|
419
|
+
EDR = 1
|
|
420
|
+
AV = 2
|
|
421
|
+
IDENTITY_PASSWORD = 3
|
|
422
|
+
EMAIL_ANTIPHISH = 4
|
|
423
|
+
EMAIL_OUTBOUND = 5
|
|
424
|
+
EMAIL_CONTENT = 6
|
|
425
|
+
EMAIL_MALWARE = 7
|
|
426
|
+
EMAIL_ATTACHMENT = 8
|
|
427
|
+
EMAIL_LINKS = 9
|
|
428
|
+
EMAIL_DKIM = 10
|
|
429
|
+
DEVICE_COMPLIANCE = 11
|
|
430
|
+
IDENTITY_MFA = 12
|
|
431
|
+
|
|
432
|
+
@classmethod
|
|
433
|
+
def _missing_(cls, value):
|
|
434
|
+
return PolicyType.INVALID
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class Platform(Enum, metaclass=MissingItem):
|
|
438
|
+
INVALID = 0
|
|
439
|
+
WINDOWS = 1
|
|
440
|
+
DARWIN = 2
|
|
441
|
+
LINUX = 3
|
|
442
|
+
ALL = 4
|
|
443
|
+
|
|
444
|
+
@classmethod
|
|
445
|
+
def _missing_(cls, value):
|
|
446
|
+
return Platform.INVALID
|
prelude_cli/cli.py
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
|
|
3
|
-
from prelude_cli.views.auth import auth
|
|
4
|
-
from prelude_cli.views.build import build
|
|
5
|
-
from prelude_cli.views.configure import configure
|
|
6
|
-
from prelude_cli.views.detect import detect
|
|
7
|
-
from prelude_cli.views.generate import generate
|
|
8
|
-
from prelude_cli.views.iam import iam
|
|
9
|
-
from prelude_cli.views.jobs import jobs
|
|
10
|
-
from prelude_cli.views.partner import partner
|
|
11
|
-
from prelude_cli.views.scm import scm
|
|
12
|
-
from prelude_sdk.models.account import Account, Keychain
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def complete_profile(ctx, param, incomplete):
|
|
16
|
-
return [x for x in Keychain().read_keychain() if x.startswith(incomplete)]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@click.group(invoke_without_command=True)
|
|
20
|
-
@click.version_option()
|
|
21
|
-
@click.pass_context
|
|
22
|
-
@click.option(
|
|
23
|
-
"--profile",
|
|
24
|
-
default="default",
|
|
25
|
-
help="The prelude keychain profile to use",
|
|
26
|
-
show_default=True,
|
|
27
|
-
shell_complete=complete_profile,
|
|
28
|
-
)
|
|
29
|
-
def cli(ctx, profile):
|
|
30
|
-
ctx.obj = Account.from_keychain(profile=profile)
|
|
31
|
-
if ctx.invoked_subcommand is None:
|
|
32
|
-
click.echo(ctx.get_help())
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
cli.add_command(auth)
|
|
36
|
-
cli.add_command(build)
|
|
37
|
-
cli.add_command(configure)
|
|
38
|
-
cli.add_command(detect)
|
|
39
|
-
cli.add_command(generate)
|
|
40
|
-
cli.add_command(iam)
|
|
41
|
-
cli.add_command(jobs)
|
|
42
|
-
cli.add_command(partner)
|
|
43
|
-
cli.add_command(scm)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if __name__ == "__main__":
|
|
47
|
-
cli()
|
prelude_cli/templates/README.md
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# $NAME
|
|
2
|
-
|
|
3
|
-
This section should describe the test, provide some background information (such as historical in-the-wild usage by threat actors or APTs), and briefly illustrate the test's intention, objective, and techniques utilized to achieve them. This section should NOT be too technical or overly long; a small paragraph should be sufficient.
|
|
4
|
-
|
|
5
|
-
## How
|
|
6
|
-
|
|
7
|
-
> Safety: This section should contain an advisory statement that positively declares that the VST does not negatively affect the tested system in any way.
|
|
8
|
-
|
|
9
|
-
Steps:
|
|
10
|
-
|
|
11
|
-
1. This section enumerates the individual, atomic steps by which ...
|
|
12
|
-
2. ... the probe attempts to achieve the intended effect of the test ...
|
|
13
|
-
3. ... and thereby perform evaluation of any resident security solutions.
|
|
14
|
-
|
|
15
|
-
Example Output:
|
|
16
|
-
```bash
|
|
17
|
-
[$ID] Starting test at: $TIME
|
|
18
|
-
[$ID] Host is vulnerable, continuing with technique execution
|
|
19
|
-
[$ID] Completed with code: 101
|
|
20
|
-
[$ID] Ending test at: $TIME
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Resolution
|
|
24
|
-
|
|
25
|
-
If this test fails:
|
|
26
|
-
|
|
27
|
-
* Bulleted list of recommendations that the testing organization SHOULD consider ...
|
|
28
|
-
* ... based upon the nature of the test, as well as the point of failure.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
ID: $ID
|
|
3
|
-
NAME: $NAME
|
|
4
|
-
TECHNIQUE: $TECHNIQUE
|
|
5
|
-
UNIT: $UNIT
|
|
6
|
-
CREATED: $TIME
|
|
7
|
-
*/
|
|
8
|
-
package main
|
|
9
|
-
|
|
10
|
-
import (
|
|
11
|
-
Endpoint "github.com/preludeorg/libraries/go/tests/endpoint"
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
func test() {
|
|
15
|
-
Endpoint.Stop(Endpoint.TestCompletedNormally)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
func clean() {
|
|
19
|
-
Endpoint.Say("Cleaning up")
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
func main() {
|
|
23
|
-
Endpoint.Start(test, clean)
|
|
24
|
-
}
|
prelude_cli/views/auth.py
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
import webbrowser
|
|
3
|
-
|
|
4
|
-
from prelude_cli.views.shared import Spinner, pretty_print
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@click.group()
|
|
8
|
-
@click.pass_context
|
|
9
|
-
def auth(ctx):
|
|
10
|
-
"""Authentication"""
|
|
11
|
-
pass
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@auth.command("login")
|
|
15
|
-
@click.option("-p", "--password", type=str, help="password for login")
|
|
16
|
-
@click.option(
|
|
17
|
-
"-t",
|
|
18
|
-
"--temp_password",
|
|
19
|
-
type=str,
|
|
20
|
-
help="temporary password for login (if set, `password` will become your new password)",
|
|
21
|
-
)
|
|
22
|
-
@click.pass_obj
|
|
23
|
-
@pretty_print
|
|
24
|
-
def login(account, password, temp_password):
|
|
25
|
-
"""Login using password or SSO"""
|
|
26
|
-
if not account.oidc:
|
|
27
|
-
password = password or click.prompt("Password", type=str, hide_input=True)
|
|
28
|
-
with Spinner(description="Logging in and saving tokens"):
|
|
29
|
-
new_password = password if temp_password else None
|
|
30
|
-
password = temp_password or password
|
|
31
|
-
return (
|
|
32
|
-
account.password_login(password, new_password),
|
|
33
|
-
"Login with password successful",
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
url = f"{account.hq.replace('api', 'platform')}/cli-auth?handle={account.handle}&provider={account.oidc}"
|
|
37
|
-
if account.oidc == "custom":
|
|
38
|
-
slug = account.slug or click.prompt("Please enter your account slug")
|
|
39
|
-
url += f"&slug={slug}"
|
|
40
|
-
webbrowser.open(url)
|
|
41
|
-
code = click.prompt(
|
|
42
|
-
f"Launching browser for authentication:\n\n{url}\n\nPlease enter your authorization code here"
|
|
43
|
-
)
|
|
44
|
-
verifier, authorization_code = code.split("/")
|
|
45
|
-
with Spinner(description="Logging in and saving tokens"):
|
|
46
|
-
tokens = account.exchange_authorization_code(authorization_code, verifier)
|
|
47
|
-
return tokens, "Login with SSO successful"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@auth.command("refresh")
|
|
51
|
-
@click.pass_obj
|
|
52
|
-
@pretty_print
|
|
53
|
-
def refresh(account):
|
|
54
|
-
"""Refresh your tokens"""
|
|
55
|
-
with Spinner(description="Refreshing tokens"):
|
|
56
|
-
return account.refresh_tokens(), "New access tokens saved"
|