mantis_api_client 5.5.0__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.
@@ -0,0 +1,805 @@
1
+ # -*- coding: utf-8 -*-
2
+ import argparse
3
+ import datetime
4
+ import json
5
+ import os
6
+ import pprint
7
+ import sys
8
+ from typing import Any
9
+
10
+ from mantis_scenario_model.lab_model import Lab
11
+
12
+ import mantis_api_client.scenario_api as scenario_api
13
+ from cr_api_client.cli_parser.provisioning_parser import add_provisioning_parser
14
+ from mantis_api_client import user_api
15
+ from mantis_api_client.cli_parser.redteam_parser import add_redteam_parser
16
+ from mantis_api_client.oidc import get_oidc_client
17
+
18
+
19
+ #
20
+ # 'lab_info_handler' handler
21
+ #
22
+ def lab_info_handler(args: Any) -> None:
23
+ # Parameters
24
+ lab_id = args.lab_id
25
+
26
+ try:
27
+ ret = scenario_api.fetch_lab(lab_id)
28
+ lab: Lab = Lab(**ret)
29
+ except Exception as e:
30
+ print(f"Error when fetching lab: '{e}'")
31
+ sys.exit(1)
32
+
33
+ if args.json:
34
+ print(lab.json())
35
+ return
36
+
37
+ lab_creation_timestamp = (
38
+ datetime.datetime.fromtimestamp(
39
+ lab.lab_creation_timestamp, datetime.timezone.utc
40
+ ).strftime("%Y-%m-%d %H:%M:%S")
41
+ + " UTC"
42
+ )
43
+
44
+ created_by = user_api.fetch_user(lab.created_by)
45
+
46
+ print("[+] Lab information:")
47
+ print(f""" [+] \033[1mContent\033[0m: {lab.name}""")
48
+ print(f""" [+] \033[1mType\033[0m: {lab.content_type.value}""")
49
+ print(f""" [+] \033[1mLab ID\033[0m: {lab.runner_id}""")
50
+ print(
51
+ f""" [+] \033[1mCreated by\033[0m: {created_by['given_name']} {created_by['last_name']} ({lab.created_by})"""
52
+ )
53
+ print(f""" [+] \033[1mStatus\033[0m: {lab.status.value}""")
54
+
55
+ print(""" [+] \033[1mTimestamps:""")
56
+
57
+ lab_creation_timestamp = (
58
+ datetime.datetime.fromtimestamp(
59
+ lab.lab_creation_timestamp, datetime.timezone.utc
60
+ ).strftime("%Y-%m-%d %H:%M:%S")
61
+ + " UTC"
62
+ )
63
+
64
+ if lab.lab_start_timestamp is not None:
65
+ lab_start_timestamp = (
66
+ datetime.datetime.fromtimestamp(
67
+ lab.lab_start_timestamp, datetime.timezone.utc
68
+ ).strftime("%Y-%m-%d %H:%M:%S")
69
+ + " UTC"
70
+ )
71
+ else:
72
+ lab_start_timestamp = str(lab.lab_start_timestamp)
73
+
74
+ if lab.lab_content_end_timestamp is not None:
75
+ lab_content_end_timestamp = (
76
+ datetime.datetime.fromtimestamp(
77
+ lab.lab_content_end_timestamp, datetime.timezone.utc
78
+ ).strftime("%Y-%m-%d %H:%M:%S")
79
+ + " UTC"
80
+ )
81
+ else:
82
+ lab_content_end_timestamp = str(lab.lab_content_end_timestamp)
83
+
84
+ if lab.lab_end_timestamp is not None:
85
+ lab_end_timestamp = (
86
+ datetime.datetime.fromtimestamp(
87
+ lab.lab_end_timestamp, datetime.timezone.utc
88
+ ).strftime("%Y-%m-%d %H:%M:%S")
89
+ + " UTC"
90
+ )
91
+ else:
92
+ lab_end_timestamp = str(lab.lab_end_timestamp)
93
+
94
+ print(f""" [+] \033[1mCreation time\033[0m: {lab_creation_timestamp}""")
95
+ print(f""" [+] \033[1mStart time\033[0m: {lab_start_timestamp}""")
96
+ print(f""" [+] \033[1mContent end time\033[0m: {lab_content_end_timestamp}""")
97
+ print(f""" [+] \033[1mLab end time\033[0m: {lab_end_timestamp}""")
98
+
99
+
100
+ #
101
+ # 'lab_api_handler' handler
102
+ #
103
+ def lab_api_handler(args: Any) -> None:
104
+ # Parameters
105
+ lab_id = args.lab_id
106
+
107
+ active_profile_domain = get_oidc_client().get_active_profile_domain(raise_exc=False)
108
+ if not active_profile_domain:
109
+ print("[+] Not authenticated")
110
+ return
111
+
112
+ it_simulation_api_url = (
113
+ f"https://app.{active_profile_domain}/proxy/{lab_id}/api/it_simulation"
114
+ )
115
+ provisioning_api_url = (
116
+ f"https://app.{active_profile_domain}/proxy/{lab_id}/api/provisioning"
117
+ )
118
+ user_activity_api_url = (
119
+ f"https://app.{active_profile_domain}/proxy/{lab_id}/api/user_activity"
120
+ )
121
+ redteam_api_url = f"https://app.{active_profile_domain}/proxy/{lab_id}/api/redteam"
122
+
123
+ if args.json:
124
+ print(
125
+ json.dumps(
126
+ {
127
+ "it_simulation_api_url": it_simulation_api_url,
128
+ "provisioning_api_url": provisioning_api_url,
129
+ "user_activity_api_url": user_activity_api_url,
130
+ "redteam_api_url": redteam_api_url,
131
+ }
132
+ )
133
+ )
134
+ return
135
+
136
+ print("[+] Lab APIs:")
137
+ print(f""" [+] \033[1mIT simulation API URL\033[0m: {it_simulation_api_url}""")
138
+ print(f""" [+] \033[1mProvisioning API URL\033[0m: {provisioning_api_url}""")
139
+ print(f""" [+] \033[1mUser activity API URL\033[0m: {user_activity_api_url}""")
140
+ print(f""" [+] \033[1mRedteam API URL\033[0m: {redteam_api_url}""")
141
+
142
+
143
+ #
144
+ # 'lab_run_handler' handler
145
+ #
146
+ def lab_run_handler(args: Any) -> None:
147
+ # Parameters
148
+ lab_id = args.lab_id
149
+
150
+ try:
151
+ scenario_api.run_lab(lab_id)
152
+ except Exception as e:
153
+ print(f"Error when running lab: '{e}'")
154
+ sys.exit(1)
155
+
156
+ print(f"[+] Lab '{lab_id}' is running")
157
+
158
+
159
+ #
160
+ # 'lab_stop_handler' handler
161
+ #
162
+ def lab_stop_handler(args: Any) -> None:
163
+ # Parameters
164
+ lab_id = args.lab_id
165
+
166
+ try:
167
+ scenario_api.stop_lab(lab_id)
168
+ except Exception as e:
169
+ print(f"Error when stopping lab: '{e}'")
170
+ sys.exit(1)
171
+
172
+ print(f"[+] Lab '{lab_id}' stopped")
173
+
174
+
175
+ #
176
+ # 'lab_delete_lab_handler' handler
177
+ #
178
+ def lab_delete_lab_handler(args: Any) -> None:
179
+ # Parameters
180
+ lab_id = args.lab_id
181
+
182
+ try:
183
+ scenario_api.delete_lab(lab_id)
184
+ except Exception as e:
185
+ print(f"Error when deleting lab ID {lab_id}: '{e}'")
186
+ sys.exit(1)
187
+
188
+ print(f"[+] Lab '{lab_id}' deleted")
189
+
190
+
191
+ #
192
+ # 'lab_resume_handler' handler
193
+ #
194
+ def lab_resume_handler(args: Any) -> None:
195
+ # Parameters
196
+ lab_id = args.lab_id
197
+
198
+ try:
199
+ scenario_api.resume_lab(lab_id)
200
+ except Exception as e:
201
+ print(f"Error when resume lab: '{e}'")
202
+ sys.exit(1)
203
+
204
+ print(f"[+] Lab '{lab_id}' resumed")
205
+
206
+
207
+ #
208
+ # 'lab_paused_status' handler
209
+ #
210
+ def lab_paused_status_handler(args: Any) -> None:
211
+ # Parameters
212
+ lab_id = args.lab_id
213
+
214
+ try:
215
+ paused_status = scenario_api.fetch_lab_paused_status(lab_id)
216
+ except Exception as e:
217
+ print(f"Error when fetching lab paused status: '{e}'")
218
+ sys.exit(1)
219
+
220
+ if args.json:
221
+ print(paused_status.json())
222
+ return
223
+
224
+ if paused_status.is_before_step is None:
225
+ position = None
226
+ elif paused_status.is_before_step is True:
227
+ position = "before"
228
+ else:
229
+ position = "after"
230
+
231
+ print(f"[+] Lab '{lab_id}' paused status:")
232
+ print(f" [+] Step: {paused_status.step}")
233
+ print(f" [+] Paused: {position}")
234
+
235
+
236
+ #
237
+ # 'lab_topology_handler' handler
238
+ #
239
+ def lab_topology_handler(args: Any) -> None:
240
+ # Parameters
241
+ lab_id = args.lab_id
242
+
243
+ try:
244
+ topology = scenario_api.fetch_lab_topology(lab_id)
245
+ except Exception as e:
246
+ print(f"Error when fetching scenario topology: '{e}'")
247
+ sys.exit(1)
248
+
249
+ if args.json:
250
+ print(topology.json())
251
+ return
252
+
253
+ print("[+] Lab topology")
254
+ print(" [+] Nodes")
255
+ for node in topology.nodes:
256
+ print(f" [+] {node.name} ({node.type})")
257
+ print(" [+] Links")
258
+ for node in topology.nodes:
259
+ if node.type == "switch":
260
+ print(f" [+] {node.name}")
261
+ for link in topology.links:
262
+ if link.switch.name == node.name:
263
+ print(f" [+] {link.node.name} - {link.params.ip}")
264
+
265
+
266
+ #
267
+ # 'lab_nodes_handler' handler
268
+ #
269
+ def lab_nodes_handler(args: Any) -> None:
270
+ # Parameters
271
+ lab_id = args.lab_id
272
+
273
+ try:
274
+ nodes = scenario_api.fetch_lab_nodes(lab_id)
275
+ except Exception as e:
276
+ print(f"Error when fetching scenario nodes: '{e}'")
277
+ sys.exit(1)
278
+
279
+ if args.json:
280
+ print(json.dumps(nodes))
281
+ return
282
+
283
+ print("[+] Lab nodes")
284
+ for node in nodes:
285
+ if node["type"] == "switch":
286
+ continue
287
+ print(f" [+] {node['name']} ({node['type']})")
288
+ print(" [+] network interfaces")
289
+
290
+ for ni in node["network_interfaces"]:
291
+ if ni["ip_address_runtime"] is not None:
292
+ ip_address = ni["ip_address_runtime"]
293
+ else:
294
+ ip_address = ni["ip_address"]
295
+ print(f" - {ip_address}")
296
+
297
+ if node["type"] == "virtual_machine":
298
+ print(" [+] Credentials")
299
+ print(
300
+ f" - username: {node['username']} - password: {node['password']}"
301
+ )
302
+ print(
303
+ f" - admin_username: {node['admin_username']} - admin_password: {node['admin_password']}"
304
+ )
305
+
306
+
307
+ #
308
+ # 'lab_assets_handler' handler
309
+ #
310
+ def lab_assets_handler(args: Any) -> None:
311
+ # Parameters
312
+ lab_id = args.lab_id
313
+
314
+ try:
315
+ assets = scenario_api.fetch_lab_assets(lab_id)
316
+ except Exception as e:
317
+ print(f"Error when fetching scenario assets: '{e}'")
318
+ sys.exit(1)
319
+
320
+ if args.json:
321
+ print(json.dumps(assets))
322
+ return
323
+
324
+ print("[+] Lab assets")
325
+ for asset in assets:
326
+ print(f" [+] {asset['name']} ({asset['type']})")
327
+ print(f" [+] roles: {asset['roles']}")
328
+ if asset["type"] == "virtual_machine":
329
+ print(f" [+] os: {asset['os']} ({asset['os_family']})")
330
+ print(" [+] network interfaces")
331
+ for ni in asset["network_interfaces"]:
332
+ print(f" - {ni['ipv4']}")
333
+ print(" [+] CPE IDs:")
334
+ for cpe in asset["cpes"]:
335
+ print(f" - {cpe}")
336
+
337
+
338
+ #
339
+ # 'lab_attack_report_handler' handler
340
+ #
341
+ def lab_attack_report_handler(args: Any) -> None:
342
+ # Parameters
343
+ lab_id = args.lab_id
344
+
345
+ try:
346
+ attack_report = scenario_api.fetch_lab_attack_report(lab_id)
347
+ except Exception as e:
348
+ print(f"Error when fetching scenario attack_report: '{e}'")
349
+ sys.exit(1)
350
+
351
+ if args.json:
352
+ print(json.dumps(attack_report))
353
+ return
354
+
355
+ print("[+] Lab attack report:")
356
+ pp = pprint.PrettyPrinter(width=160)
357
+ pp.pprint(attack_report)
358
+
359
+
360
+ #
361
+ # 'lab_attack_infras_handler' handler
362
+ #
363
+ def lab_attack_infras_handler(args: Any) -> None:
364
+ # Parameters
365
+ lab_id = args.lab_id
366
+
367
+ try:
368
+ attack_infras = scenario_api.fetch_lab_attack_infras(lab_id)
369
+ except Exception as e:
370
+ print(f"Error when fetching scenario attack_infras: '{e}'")
371
+ sys.exit(1)
372
+
373
+ if args.json:
374
+ print(json.dumps(attack_infras))
375
+ return
376
+
377
+ print("[+] Lab attack infrastructures:")
378
+ for infra in attack_infras:
379
+ print(f" [+] {infra}")
380
+
381
+
382
+ #
383
+ # 'lab_attack_sessions_handler' handler
384
+ #
385
+ def lab_attack_sessions_handler(args: Any) -> None:
386
+ # Parameters
387
+ lab_id = args.lab_id
388
+
389
+ try:
390
+ attack_sessions = scenario_api.fetch_lab_attack_sessions(lab_id)
391
+ except Exception as e:
392
+ print(f"Error when fetching scenario attack_sessions: '{e}'")
393
+ sys.exit(1)
394
+
395
+ if args.json:
396
+ print(json.dumps(attack_sessions))
397
+ return
398
+
399
+ knowledge = scenario_api.fetch_lab_attack_knowledge(lab_id)
400
+
401
+ print("[+] Lab attack sessions:")
402
+ for session in attack_sessions:
403
+ compromised_host_ip = None
404
+ if "hosts" in knowledge:
405
+ for host in knowledge["hosts"]:
406
+ for nic in host:
407
+ if nic is not None:
408
+ if "ip" in nic and "idHost" in nic:
409
+ if nic["idHost"] == session["idHost"]:
410
+ compromised_host_ip = nic["ip"]
411
+ print(
412
+ f" [+] {session['idAttackSession']} - compromised host: {compromised_host_ip} - type: {session['type']} - direct_access: {session['direct_access']} - privilege_level: {session['privilege_level']} - uuid: {session['identifier']}"
413
+ )
414
+
415
+
416
+ #
417
+ # 'lab_attack_knowledge_handler' handler
418
+ #
419
+ def lab_attack_knowledge_handler(args: Any) -> None:
420
+ # Parameters
421
+ lab_id = args.lab_id
422
+
423
+ try:
424
+ attack_knowledge = scenario_api.fetch_lab_attack_knowledge(lab_id)
425
+ except Exception as e:
426
+ print(f"Error when fetching scenario attack_knowledge: '{e}'")
427
+ sys.exit(1)
428
+
429
+ if args.json:
430
+ print(json.dumps(attack_knowledge))
431
+ return
432
+
433
+ print("[+] Lab attack knowledge:")
434
+ pp = pprint.PrettyPrinter(compact=True, width=160)
435
+ pp.pprint(attack_knowledge)
436
+
437
+
438
+ #
439
+ # 'lab_notifications_handler' handler
440
+ #
441
+ def lab_notifications_handler(args: Any) -> None:
442
+ # Parameters
443
+ lab_id = args.lab_id
444
+
445
+ try:
446
+ notifications = scenario_api.fetch_lab_notifications(lab_id)
447
+ except Exception as e:
448
+ print(f"Error when fetching scenario notifications: '{e}'")
449
+ sys.exit(1)
450
+
451
+ if args.json:
452
+ print(json.dumps(notifications))
453
+ return
454
+
455
+ print("[+] Lab notifications")
456
+ for notification in notifications:
457
+ event = json.loads(notification)
458
+ print(f"⚡ {event['event_datetime']} - {event['event_data']}")
459
+
460
+
461
+ #
462
+ # 'lab_config_handler' handler
463
+ #
464
+ def lab_config_handler(args: Any) -> None:
465
+ # Parameters
466
+ lab_id = args.lab_id
467
+
468
+ try:
469
+ lab_config = scenario_api.fetch_lab_config(lab_id)
470
+ except Exception as e:
471
+ print(f"Error when fetching lab config: '{e}'")
472
+ sys.exit(1)
473
+
474
+ if args.json:
475
+ print(lab_config.model_dump(mode="json"))
476
+ return
477
+
478
+ print("[+] Lab lab_config:")
479
+ pp = pprint.PrettyPrinter(width=160)
480
+ pp.pprint(lab_config.dict())
481
+
482
+
483
+ def set_current_lab(lab_id: str):
484
+ """Setting current lab means activating environment variables to
485
+ set cr_api_client lib access to a specific running Cyber Range
486
+ instance.
487
+
488
+ """
489
+
490
+ active_profile_domain = get_oidc_client().get_active_profile_domain(raise_exc=False)
491
+ if not active_profile_domain:
492
+ print("[+] Not authenticated")
493
+ return
494
+
495
+ os.environ["CORE_API_URL"] = (
496
+ f"https://app.{active_profile_domain}/proxy/{lab_id}/api/it_simulation"
497
+ )
498
+ os.environ["PROVISIONING_API_URL"] = (
499
+ f"https://app.{active_profile_domain}/proxy/{lab_id}/api/provisioning"
500
+ )
501
+ os.environ["USER_ACTIVITY_API_URL"] = (
502
+ f"https://app.{active_profile_domain}/proxy/{lab_id}/api/user_activity"
503
+ )
504
+ os.environ["REDTEAM_API_URL"] = (
505
+ f"https://app.{active_profile_domain}/proxy/{lab_id}/api/redteam"
506
+ )
507
+
508
+
509
+ def unset_current_lab():
510
+ """Unsetting current lab means deactivating environment variables used to
511
+ set cr_api_client lib access to a specific running Cyber Range
512
+ instance.
513
+
514
+ """
515
+
516
+ del os.environ["CORE_API_URL"]
517
+ del os.environ["PROVISIONING_API_URL"]
518
+ del os.environ["USER_ACTIVITY_API_URL"]
519
+ del os.environ["REDTEAM_API_URL"]
520
+
521
+
522
+ def lab_set_lab_handler(args: Any) -> None:
523
+ # Parameters
524
+ lab_id = args.lab_id
525
+
526
+ set_current_lab(lab_id)
527
+
528
+
529
+ def lab_unset_lab_handler(args: Any) -> None:
530
+ unset_current_lab()
531
+
532
+
533
+ #
534
+ # 'lab_get_remote_access_handler' handler
535
+ #
536
+ def lab_get_remote_access_handler(args: Any) -> None:
537
+ # Parameters
538
+ lab_id = args.lab_id
539
+
540
+ try:
541
+ remote_access = scenario_api.fetch_lab_remote_access(lab_id)
542
+ except Exception as e:
543
+ print(f"Error when fetching lab remote access info: '{e}'")
544
+ sys.exit(1)
545
+
546
+ if args.json:
547
+ print(remote_access.json())
548
+ return
549
+
550
+ print("[+] Lab remote access information:")
551
+ print(f"[+] \033[1mLab ID\033[0m: {lab_id}")
552
+ for node in remote_access.nodes:
553
+ print(f" [+] \033[1mNode name\033[0m: {node.name}")
554
+ print(f" [+] \033[1mHTTP URL\033[0m: {node.http_url}")
555
+
556
+ if len(node.credentials) > 0:
557
+ print(" [+] \033[1mCredentials\033[0m:")
558
+ for credential in node.credentials:
559
+ print(" ----")
560
+ print(f" [+] \033[1mLogin\033[0m: {credential.login}")
561
+ print(f" [+] \033[1mPassword\033[0m: {credential.password}")
562
+ print(f" [+] \033[1mPrivilege\033[0m: {credential.privilege}")
563
+
564
+
565
+ #
566
+ # 'lab_get_security_alerts_handler' handler
567
+ #
568
+ def lab_get_security_alerts_handler(args: Any) -> None:
569
+ # Parameters
570
+ lab_id = args.lab_id
571
+
572
+ try:
573
+ security_alerts = scenario_api.fetch_lab_security_alerts(lab_id)
574
+ except Exception as e:
575
+ print(f"Error when fetching lab security alerts: '{e}'")
576
+ sys.exit(1)
577
+
578
+ if args.json:
579
+ for security_product, alerts in security_alerts.items():
580
+ for alert in alerts:
581
+ print(alert.json())
582
+ return
583
+
584
+ print(f"[+] \033[1mLab ID\033[0m: {lab_id}")
585
+ for security_product, alerts in security_alerts.items():
586
+ print(f"[+] \033[1mAlerts from {security_product}:\033[0m")
587
+
588
+ for alert in alerts:
589
+ print(f" [+] \033[1mAlert ID\033[0m: {alert.alert_id}")
590
+ print(f" \033[1mAlert name\033[0m: {alert.alert_name}")
591
+ print(f" \033[1mAlert status\033[0m: {alert.alert_status.value}")
592
+ print(f" \033[1mTarget\033[0m: {alert.asset_hostname}")
593
+ print(
594
+ f" \033[1mAssociated log dates\033[0m: start:{alert.start_time} - end:{alert.end_time}"
595
+ )
596
+ print(
597
+ f" \033[1mCorrelated attack IDs\033[0m: {alert.correlated_attacks}"
598
+ )
599
+
600
+
601
+ def add_lab_parser(root_parser: argparse.ArgumentParser, subparsers: Any) -> None:
602
+ # Subparser lab
603
+ parser_lab = subparsers.add_parser(
604
+ "lab",
605
+ help="Scenario API related commands (lab)",
606
+ formatter_class=root_parser.formatter_class,
607
+ )
608
+ parser_lab.set_defaults(set_lab=lab_set_lab_handler)
609
+ parser_lab.set_defaults(unset_lab=lab_unset_lab_handler)
610
+ parser_lab.add_argument("lab_id", type=str, help="The lab id")
611
+ subparsers_lab = parser_lab.add_subparsers()
612
+
613
+ # 'lab_info' command
614
+ parser_lab_info = subparsers_lab.add_parser(
615
+ "info",
616
+ help="Get information about a lab",
617
+ formatter_class=root_parser.formatter_class,
618
+ )
619
+ parser_lab_info.set_defaults(func=lab_info_handler)
620
+ parser_lab_info.add_argument(
621
+ "--json", help="Return JSON result.", action="store_true"
622
+ )
623
+
624
+ # 'lab_api' command
625
+ parser_lab_api = subparsers_lab.add_parser(
626
+ "api",
627
+ help="Get API URLs to directly access the lab",
628
+ formatter_class=root_parser.formatter_class,
629
+ )
630
+ parser_lab_api.set_defaults(func=lab_api_handler)
631
+ parser_lab_api.add_argument(
632
+ "--json", help="Return JSON result.", action="store_true"
633
+ )
634
+
635
+ # 'lab_run' command
636
+ parser_lab_run = subparsers_lab.add_parser(
637
+ "run", help="Run a specific lab", formatter_class=root_parser.formatter_class
638
+ )
639
+ parser_lab_run.set_defaults(func=lab_run_handler)
640
+
641
+ # 'lab_stop' command
642
+ parser_lab_stop = subparsers_lab.add_parser(
643
+ "stop", help="Stop a specific lab", formatter_class=root_parser.formatter_class
644
+ )
645
+ parser_lab_stop.set_defaults(func=lab_stop_handler)
646
+
647
+ # 'lab_delete_lab' command
648
+ parser_lab_delete_lab = subparsers_lab.add_parser(
649
+ "delete",
650
+ help="Delete lab from its lab id",
651
+ formatter_class=root_parser.formatter_class,
652
+ )
653
+ parser_lab_delete_lab.set_defaults(func=lab_delete_lab_handler)
654
+
655
+ # 'lab_resume' command
656
+ parser_lab_resume = subparsers_lab.add_parser(
657
+ "resume",
658
+ help="Resume a specific lab",
659
+ formatter_class=root_parser.formatter_class,
660
+ )
661
+ parser_lab_resume.set_defaults(func=lab_resume_handler)
662
+
663
+ # 'lab_paused_status' command
664
+ parser_lab_paused_status = subparsers_lab.add_parser(
665
+ "paused-status",
666
+ help="Show current lab paused status",
667
+ formatter_class=root_parser.formatter_class,
668
+ )
669
+ parser_lab_paused_status.set_defaults(func=lab_paused_status_handler)
670
+ parser_lab_paused_status.add_argument(
671
+ "--json", help="Return JSON result.", action="store_true"
672
+ )
673
+
674
+ # 'lab_topology' command
675
+ parser_lab_topology = subparsers_lab.add_parser(
676
+ "topology",
677
+ help="Get scenario topology on current lab",
678
+ formatter_class=root_parser.formatter_class,
679
+ )
680
+ parser_lab_topology.set_defaults(func=lab_topology_handler)
681
+ parser_lab_topology.add_argument(
682
+ "--json", help="Return JSON result.", action="store_true"
683
+ )
684
+
685
+ # 'lab_nodes' command
686
+ parser_lab_nodes = subparsers_lab.add_parser(
687
+ "nodes",
688
+ help="Get scenario nodes on current lab",
689
+ formatter_class=root_parser.formatter_class,
690
+ )
691
+ parser_lab_nodes.set_defaults(func=lab_nodes_handler)
692
+ parser_lab_nodes.add_argument(
693
+ "--json", help="Return JSON result.", action="store_true"
694
+ )
695
+
696
+ # 'lab_assets' command
697
+ parser_lab_assets = subparsers_lab.add_parser(
698
+ "assets",
699
+ help="Get scenario assets on current lab",
700
+ formatter_class=root_parser.formatter_class,
701
+ )
702
+ parser_lab_assets.set_defaults(func=lab_assets_handler)
703
+ parser_lab_assets.add_argument(
704
+ "--json", help="Return JSON result.", action="store_true"
705
+ )
706
+
707
+ # 'lab_attack_report' command
708
+ parser_lab_attack_report = subparsers_lab.add_parser(
709
+ "attack-report",
710
+ help="Get scenario attack report on current lab",
711
+ formatter_class=root_parser.formatter_class,
712
+ )
713
+ parser_lab_attack_report.set_defaults(func=lab_attack_report_handler)
714
+ parser_lab_attack_report.add_argument(
715
+ "--json", help="Return JSON result.", action="store_true"
716
+ )
717
+
718
+ # 'lab_attack_infras' command
719
+ parser_lab_attack_infras = subparsers_lab.add_parser(
720
+ "attack-infras",
721
+ help="Get scenario attack infras on current lab",
722
+ formatter_class=root_parser.formatter_class,
723
+ )
724
+ parser_lab_attack_infras.set_defaults(func=lab_attack_infras_handler)
725
+ parser_lab_attack_infras.add_argument(
726
+ "--json", help="Return JSON result.", action="store_true"
727
+ )
728
+
729
+ # 'lab_attack_sessions' command
730
+ parser_lab_attack_sessions = subparsers_lab.add_parser(
731
+ "attack-sessions",
732
+ help="Get scenario attack sessions on current lab",
733
+ formatter_class=root_parser.formatter_class,
734
+ )
735
+ parser_lab_attack_sessions.set_defaults(func=lab_attack_sessions_handler)
736
+ parser_lab_attack_sessions.add_argument(
737
+ "--json", help="Return JSON result.", action="store_true"
738
+ )
739
+
740
+ # 'lab_attack_knowledge' command
741
+ parser_lab_attack_knowledge = subparsers_lab.add_parser(
742
+ "attack-knowledge",
743
+ help="Get scenario attack knowledge on current lab",
744
+ formatter_class=root_parser.formatter_class,
745
+ )
746
+ parser_lab_attack_knowledge.set_defaults(func=lab_attack_knowledge_handler)
747
+ parser_lab_attack_knowledge.add_argument(
748
+ "--json", help="Return JSON result.", action="store_true"
749
+ )
750
+
751
+ # 'lab_notifications' command
752
+ parser_lab_notifications = subparsers_lab.add_parser(
753
+ "notifications",
754
+ help="Get scenario notifications on current lab",
755
+ formatter_class=root_parser.formatter_class,
756
+ )
757
+ parser_lab_notifications.set_defaults(func=lab_notifications_handler)
758
+ parser_lab_notifications.add_argument(
759
+ "--json", help="Return JSON result.", action="store_true"
760
+ )
761
+
762
+ # 'lab_config' command
763
+ parser_lab_config = subparsers_lab.add_parser(
764
+ "lab-config",
765
+ help="Get lab config on current lab",
766
+ formatter_class=root_parser.formatter_class,
767
+ )
768
+ parser_lab_config.set_defaults(func=lab_config_handler)
769
+ parser_lab_config.add_argument(
770
+ "--json", help="Return JSON result.", action="store_true"
771
+ )
772
+
773
+ # 'lab_get_remote_access' command
774
+ parser_lab_get_remote_access = subparsers_lab.add_parser(
775
+ "remote-access",
776
+ help="Get info for remote access to lab VMs",
777
+ )
778
+ parser_lab_get_remote_access.set_defaults(func=lab_get_remote_access_handler)
779
+ parser_lab_get_remote_access.add_argument(
780
+ "--json", help="Return JSON result.", action="store_true"
781
+ )
782
+
783
+ # 'lab_get_security_alerts' command
784
+ parser_lab_get_security_alerts = subparsers_lab.add_parser(
785
+ "alerts",
786
+ help="Get triggered security alerts from supported security products (currently only MS Sentinel)",
787
+ )
788
+ parser_lab_get_security_alerts.set_defaults(func=lab_get_security_alerts_handler)
789
+ parser_lab_get_security_alerts.add_argument(
790
+ "--json", help="Return JSON result.", action="store_true"
791
+ )
792
+
793
+ parser_lab.set_defaults(func=lambda _: parser_lab.print_help())
794
+
795
+ # -------------------
796
+ # --- Redteam actions on labs
797
+ # -------------------
798
+
799
+ add_redteam_parser(root_parser=root_parser, subparsers=subparsers_lab)
800
+
801
+ # -------------------
802
+ # --- Provisioning actions on labs
803
+ # -------------------
804
+
805
+ add_provisioning_parser(root_parser=root_parser, subparsers=subparsers_lab)