runbooks 1.1.9__py3-none-any.whl → 1.1.10__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.
Files changed (107) hide show
  1. runbooks/__init__.py +1 -1
  2. runbooks/__init___optimized.py +2 -1
  3. runbooks/_platform/__init__.py +1 -1
  4. runbooks/cfat/cli.py +4 -3
  5. runbooks/cfat/cloud_foundations_assessment.py +1 -2
  6. runbooks/cfat/tests/test_cli.py +4 -1
  7. runbooks/cli/commands/finops.py +68 -19
  8. runbooks/cli/commands/inventory.py +796 -7
  9. runbooks/cli/commands/operate.py +65 -4
  10. runbooks/cloudops/cost_optimizer.py +1 -3
  11. runbooks/common/cli_decorators.py +6 -4
  12. runbooks/common/config_loader.py +787 -0
  13. runbooks/common/config_schema.py +280 -0
  14. runbooks/common/dry_run_framework.py +14 -2
  15. runbooks/common/mcp_integration.py +238 -0
  16. runbooks/finops/ebs_cost_optimizer.py +7 -4
  17. runbooks/finops/elastic_ip_optimizer.py +7 -4
  18. runbooks/finops/infrastructure/__init__.py +3 -2
  19. runbooks/finops/infrastructure/commands.py +7 -4
  20. runbooks/finops/infrastructure/load_balancer_optimizer.py +7 -4
  21. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +7 -4
  22. runbooks/finops/nat_gateway_optimizer.py +7 -4
  23. runbooks/finops/tests/run_tests.py +1 -1
  24. runbooks/inventory/ArgumentsClass.py +2 -1
  25. runbooks/inventory/README.md +111 -12
  26. runbooks/inventory/Tests/test_Inventory_Modules.py +27 -10
  27. runbooks/inventory/Tests/test_cfn_describe_stacks.py +18 -7
  28. runbooks/inventory/Tests/test_ec2_describe_instances.py +30 -15
  29. runbooks/inventory/Tests/test_lambda_list_functions.py +17 -3
  30. runbooks/inventory/Tests/test_org_list_accounts.py +17 -4
  31. runbooks/inventory/account_class.py +0 -1
  32. runbooks/inventory/all_my_instances_wrapper.py +4 -8
  33. runbooks/inventory/aws_organization.png +0 -0
  34. runbooks/inventory/check_cloudtrail_compliance.py +4 -4
  35. runbooks/inventory/check_controltower_readiness.py +50 -47
  36. runbooks/inventory/check_landingzone_readiness.py +35 -31
  37. runbooks/inventory/cloud_foundations_integration.py +8 -3
  38. runbooks/inventory/core/collector.py +201 -1
  39. runbooks/inventory/discovery.md +2 -1
  40. runbooks/inventory/{draw_org_structure.py → draw_org.py} +55 -9
  41. runbooks/inventory/drift_detection_cli.py +8 -68
  42. runbooks/inventory/find_cfn_drift_detection.py +14 -4
  43. runbooks/inventory/find_cfn_orphaned_stacks.py +7 -5
  44. runbooks/inventory/find_cfn_stackset_drift.py +5 -5
  45. runbooks/inventory/find_ec2_security_groups.py +6 -3
  46. runbooks/inventory/find_landingzone_versions.py +5 -5
  47. runbooks/inventory/find_vpc_flow_logs.py +5 -5
  48. runbooks/inventory/inventory.sh +20 -7
  49. runbooks/inventory/inventory_mcp_cli.py +4 -0
  50. runbooks/inventory/inventory_modules.py +9 -7
  51. runbooks/inventory/list_cfn_stacks.py +18 -8
  52. runbooks/inventory/list_cfn_stackset_operation_results.py +2 -2
  53. runbooks/inventory/list_cfn_stackset_operations.py +32 -20
  54. runbooks/inventory/list_cfn_stacksets.py +7 -4
  55. runbooks/inventory/list_config_recorders_delivery_channels.py +4 -4
  56. runbooks/inventory/list_ds_directories.py +3 -3
  57. runbooks/inventory/list_ec2_availability_zones.py +7 -3
  58. runbooks/inventory/list_ec2_ebs_volumes.py +3 -3
  59. runbooks/inventory/list_ec2_instances.py +1 -1
  60. runbooks/inventory/list_ecs_clusters_and_tasks.py +8 -4
  61. runbooks/inventory/list_elbs_load_balancers.py +7 -3
  62. runbooks/inventory/list_enis_network_interfaces.py +3 -3
  63. runbooks/inventory/list_guardduty_detectors.py +9 -5
  64. runbooks/inventory/list_iam_policies.py +7 -3
  65. runbooks/inventory/list_iam_roles.py +3 -3
  66. runbooks/inventory/list_iam_saml_providers.py +8 -4
  67. runbooks/inventory/list_lambda_functions.py +8 -4
  68. runbooks/inventory/list_org_accounts.py +306 -276
  69. runbooks/inventory/list_org_accounts_users.py +45 -9
  70. runbooks/inventory/list_rds_db_instances.py +4 -4
  71. runbooks/inventory/list_route53_hosted_zones.py +3 -3
  72. runbooks/inventory/list_servicecatalog_provisioned_products.py +5 -5
  73. runbooks/inventory/list_sns_topics.py +4 -4
  74. runbooks/inventory/list_ssm_parameters.py +6 -3
  75. runbooks/inventory/list_vpc_subnets.py +8 -4
  76. runbooks/inventory/list_vpcs.py +15 -4
  77. runbooks/inventory/mcp_vpc_validator.py +6 -0
  78. runbooks/inventory/organizations_discovery.py +17 -3
  79. runbooks/inventory/organizations_utils.py +553 -0
  80. runbooks/inventory/output_formatters.py +422 -0
  81. runbooks/inventory/recover_cfn_stack_ids.py +5 -5
  82. runbooks/inventory/run_on_multi_accounts.py +3 -3
  83. runbooks/inventory/tag_coverage.py +481 -0
  84. runbooks/inventory/validation_utils.py +358 -0
  85. runbooks/inventory/verify_ec2_security_groups.py +18 -5
  86. runbooks/inventory/vpc_architecture_validator.py +7 -1
  87. runbooks/inventory/vpc_dependency_analyzer.py +6 -0
  88. runbooks/main_final.py +2 -2
  89. runbooks/main_ultra_minimal.py +2 -2
  90. runbooks/mcp/integration.py +6 -4
  91. runbooks/remediation/acm_remediation.py +2 -2
  92. runbooks/remediation/cloudtrail_remediation.py +2 -2
  93. runbooks/remediation/cognito_remediation.py +2 -2
  94. runbooks/remediation/dynamodb_remediation.py +2 -2
  95. runbooks/remediation/ec2_remediation.py +2 -2
  96. runbooks/remediation/kms_remediation.py +2 -2
  97. runbooks/remediation/lambda_remediation.py +2 -2
  98. runbooks/remediation/rds_remediation.py +2 -2
  99. runbooks/remediation/s3_remediation.py +1 -1
  100. runbooks/vpc/cloudtrail_audit_integration.py +1 -1
  101. {runbooks-1.1.9.dist-info → runbooks-1.1.10.dist-info}/METADATA +74 -4
  102. {runbooks-1.1.9.dist-info → runbooks-1.1.10.dist-info}/RECORD +106 -100
  103. runbooks/__init__.py.backup +0 -134
  104. {runbooks-1.1.9.dist-info → runbooks-1.1.10.dist-info}/WHEEL +0 -0
  105. {runbooks-1.1.9.dist-info → runbooks-1.1.10.dist-info}/entry_points.txt +0 -0
  106. {runbooks-1.1.9.dist-info → runbooks-1.1.10.dist-info}/licenses/LICENSE +0 -0
  107. {runbooks-1.1.9.dist-info → runbooks-1.1.10.dist-info}/top_level.txt +0 -0
@@ -8,14 +8,17 @@ from queue import Queue
8
8
  from threading import Thread
9
9
  from time import time
10
10
 
11
- import Inventory_Modules
12
- from account_class import aws_acct_access
13
- from ArgumentsClass import CommonArguments
11
+ from runbooks.inventory import inventory_modules as Inventory_Modules
12
+ from runbooks.inventory.account_class import aws_acct_access
13
+ from runbooks.inventory.ArgumentsClass import CommonArguments
14
14
  from botocore.exceptions import ClientError
15
- from runbooks.common.rich_utils import console, print_success, print_error, print_info
16
- from runbooks.common.rich_utils import console, create_table
15
+ from runbooks.common.rich_utils import console, print_success, print_error, print_info, create_table
16
+ from runbooks import __version__
17
17
 
18
- __version__ = "2024.05.18"
18
+
19
+
20
+ # Terminal control constants
21
+ ERASE_LINE = '\x1b[2K'
19
22
 
20
23
  script_path, script_name = os.path.split(sys.argv[0])
21
24
  parser = CommonArguments()
@@ -210,7 +213,7 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
210
213
  print(
211
214
  f"The following list of roles were tried, but none were allowed access to account {fChildAccountId} using the {aws_account.acct_number} account in region {fRegion}"
212
215
  )
213
- print(Fore.RED, CTRoles, Fore.RESET)
216
+ console.print(f"[red]{CTRoles}[/red]")
214
217
  logging.debug(account_credentials)
215
218
  ProcessStatus[Step]["Success"] = False
216
219
  sys.exit("Exiting due to cross-account access failure")
@@ -277,18 +280,18 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
277
280
  logging.error(DelConfigService["ErrorMessage"])
278
281
 
279
282
  if ProcessStatus[Step]["Success"]:
280
- print(f"{ERASE_LINE + Fore.GREEN}** {Step} completed with no issues") if verbose < 50 else None
283
+ print(f"{ERASE_LINE}** {Step} completed with no issues") if verbose < 50 else None
281
284
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
282
285
  print(
283
- f"{ERASE_LINE + Fore.GREEN}** {Step} found {ProcessStatus[Step]['IssuesFound']} issue, but we were able to fix it"
286
+ f"{ERASE_LINE}** {Step} found {ProcessStatus[Step]['IssuesFound']} issue, but we were able to fix it"
284
287
  ) if verbose < 50 else None
285
288
  ProcessStatus[Step]["Success"] = True
286
289
  elif ProcessStatus[Step]["IssuesFound"] > ProcessStatus[Step]["IssuesFixed"]:
287
290
  print(
288
- f"{ERASE_LINE + Fore.RED}** {Step} completed, but there was {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blocker found that wasn't fixed"
291
+ f"{ERASE_LINE}** {Step} completed, but there was {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blocker found that wasn't fixed"
289
292
  ) if verbose < 50 else None
290
293
  else:
291
- print(f"{ERASE_LINE + Fore.RED}** {Step} completed with blockers found") if verbose < 50 else None
294
+ print(f"{ERASE_LINE}** {Step} completed with blockers found") if verbose < 50 else None
292
295
  print() if verbose < 50 else None
293
296
 
294
297
  # Step 2
@@ -341,7 +344,7 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
341
344
  logging.warning(
342
345
  f"[red]Found a config recorder for account %s in region %s",
343
346
  ConfigList[_]["AccountID"],
344
- ConfigList[_]["Region"] + Fore.RESET,
347
+ ConfigList[_]["Region"],
345
348
  )
346
349
  ProcessStatus[Step]["Success"] = False
347
350
  ProcessStatus[Step]["IssuesFound"] += 1
@@ -379,18 +382,18 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
379
382
  ProcessStatus[Step]["IssuesFixed"] += 1
380
383
 
381
384
  if ProcessStatus[Step]["Success"]:
382
- print(f"{ERASE_LINE + Fore.GREEN}** Step 2 completed with no issues") if verbose < 50 else None
385
+ print(f"{ERASE_LINE}** Step 2 completed with no issues") if verbose < 50 else None
383
386
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
384
387
  print(
385
- f"{ERASE_LINE + Fore.GREEN}** Step 2 found {ProcessStatus[Step]['IssuesFound']} issues, but they were fixed by deleting the existing Config Recorders and Delivery Channels"
388
+ f"{ERASE_LINE}** Step 2 found {ProcessStatus[Step]['IssuesFound']} issues, but they were fixed by deleting the existing Config Recorders and Delivery Channels"
386
389
  ) if verbose < 50 else None
387
390
  ProcessStatus[Step]["Success"] = True
388
391
  elif ProcessStatus[Step]["IssuesFound"] > ProcessStatus[Step]["IssuesFixed"]:
389
392
  print(
390
- f"{ERASE_LINE + Fore.RED}** Step 2 completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} items found that weren't deleted"
393
+ f"{ERASE_LINE}** Step 2 completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} items found that weren't deleted"
391
394
  ) if verbose < 50 else None
392
395
  else:
393
- print(f"{ERASE_LINE + Fore.RED}** Step 2 completed with blockers found") if verbose < 50 else None
396
+ print(f"{ERASE_LINE}** Step 2 completed with blockers found") if verbose < 50 else None
394
397
  print() if verbose < 50 else None
395
398
 
396
399
  # Step 3
@@ -434,18 +437,18 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
434
437
  print(my_Error)
435
438
 
436
439
  if ProcessStatus[Step]["Success"]:
437
- print(f"{ERASE_LINE + Fore.GREEN}** {Step} completed with no issues") if verbose < 50 else None
440
+ print(f"{ERASE_LINE}** {Step} completed with no issues") if verbose < 50 else None
438
441
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
439
442
  print(
440
- f"{ERASE_LINE + Fore.GREEN}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but they were fixed by deleting the existing CloudTrail trail names"
443
+ f"{ERASE_LINE}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but they were fixed by deleting the existing CloudTrail trail names"
441
444
  ) if verbose < 50 else None
442
445
  ProcessStatus[Step]["Success"] = True
443
446
  elif ProcessStatus[Step]["IssuesFound"] > ProcessStatus[Step]["IssuesFixed"]:
444
447
  print(
445
- f"{ERASE_LINE + Fore.RED}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} trail names found that wasn't deleted"
448
+ f"{ERASE_LINE}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} trail names found that wasn't deleted"
446
449
  ) if verbose < 50 else None
447
450
  else:
448
- print(f"{ERASE_LINE + Fore.RED}** {Step} completed with blockers found") if verbose < 50 else None
451
+ print(f"{ERASE_LINE}** {Step} completed with blockers found") if verbose < 50 else None
449
452
  print() if verbose < 50 else None
450
453
 
451
454
  """ Step 4
@@ -453,11 +456,11 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
453
456
  # 4. This section checks for a pending guard duty invite. You can also check from the Guard Duty Console
454
457
  Step='Step4'
455
458
  try:
456
- print(Fore.BLUE + "{}:".format(Step) + Fore.RESET)
459
+ print("{}:".format(Step))
457
460
  print(" Checking account {} for any GuardDuty invites".format(fChildAccountId))
458
461
  GDinvites2=[]
459
462
  for region in fRegionList:
460
- logging.warning("Checking account %s in region %s for", fChildAccountId, region+Fore.RED+" GuardDuty"+Fore.RESET+" invitations")
463
+ logging.warning("Checking account %s in region %s for", fChildAccountId, region+" GuardDuty"+" invitations")
461
464
  logging.warning("Checking account %s in region %s for GuardDuty invites", fChildAccountId, region)
462
465
  GDinvites=Inventory_Modules.find_gd_invites(account_credentials, region)
463
466
  if len(GDinvites) > 0:
@@ -475,7 +478,7 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
475
478
  ProcessStatus[Step]['Success']=False
476
479
 
477
480
  for i in range(len(GDinvites2)):
478
- logging.warning(Fore.RED+"I found a GuardDuty invitation for account %s in region %s from account %s ", fChildAccountId, GDinvites2[i]['Region'], GDinvites2[i]['AccountId']+Fore.RESET)
481
+ logging.warning("I found a GuardDuty invitation for account %s in region %s from account %s ", fChildAccountId, GDinvites2[i]['Region'], GDinvites2[i]['AccountId'])
479
482
  ProcessStatus[Step]['IssuesFound']+=1
480
483
  ProcessStatus[Step]['Success']=False
481
484
  if fFixRun:
@@ -489,14 +492,14 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
489
492
  print(my_Error)
490
493
 
491
494
  if ProcessStatus[Step]['Success']:
492
- print(ERASE_LINE+Fore.GREEN+"** {} completed with no issues".format(Step)+Fore.RESET)
495
+ print(ERASE_LINE+"** {} completed with no issues".format(Step))
493
496
  elif ProcessStatus[Step]['IssuesFound']-ProcessStatus[Step]['IssuesFixed']==0:
494
- print(ERASE_LINE+Fore.GREEN+"** {} found {} guardduty invites, but they were deleted".format(Step,ProcessStatus[Step]['IssuesFound'])+Fore.RESET)
497
+ print(ERASE_LINE+"** {} found {} guardduty invites, but they were deleted".format(Step,ProcessStatus[Step]['IssuesFound']))
495
498
  ProcessStatus[Step]['Success']=True
496
499
  elif (ProcessStatus[Step]['IssuesFound']>ProcessStatus[Step]['IssuesFixed']):
497
- print(ERASE_LINE+Fore.RED+"** {} completed, but there were {} guardduty invites found that couldn't be deleted".format(Step,ProcessStatus[Step]['IssuesFound']-ProcessStatus[Step]['IssuesFixed'])+Fore.RESET)
500
+ print(ERASE_LINE+"** {} completed, but there were {} guardduty invites found that couldn't be deleted".format(Step,ProcessStatus[Step]['IssuesFound']-ProcessStatus[Step]['IssuesFixed']))
498
501
  else:
499
- print(ERASE_LINE+Fore.RED+"** {} completed with blockers found".format(Step)+Fore.RESET)
502
+ print(ERASE_LINE+"** {} completed with blockers found".format(Step))
500
503
  print()
501
504
  """
502
505
 
@@ -528,18 +531,18 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
528
531
  print("Which it is - so ...") if verbose < 50 else None
529
532
 
530
533
  if ProcessStatus[Step]["Success"]:
531
- print(f"{ERASE_LINE + Fore.GREEN}** {Step} completed with no issues") if verbose < 50 else None
534
+ print(f"{ERASE_LINE}** {Step} completed with no issues") if verbose < 50 else None
532
535
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
533
536
  print(
534
- f"{ERASE_LINE + Fore.GREEN}** {Step} found {ProcessStatus[Step]['IssuesFound']} issue, but we were able to fix it"
537
+ f"{ERASE_LINE}** {Step} found {ProcessStatus[Step]['IssuesFound']} issue, but we were able to fix it"
535
538
  ) if verbose < 50 else None
536
539
  ProcessStatus[Step]["Success"] = True
537
540
  elif ProcessStatus[Step]["IssuesFound"] > ProcessStatus[Step]["IssuesFixed"]:
538
541
  print(
539
- f"{ERASE_LINE + Fore.RED}** {Step} completed, but there was {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blocker found that wasn't fixed"
542
+ f"{ERASE_LINE}** {Step} completed, but there was {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blocker found that wasn't fixed"
540
543
  ) if verbose < 50 else None
541
544
  else:
542
- print(f"{ERASE_LINE + Fore.RED}** {Step} completed with blockers found") if verbose < 50 else None
545
+ print(f"{ERASE_LINE}** {Step} completed with blockers found") if verbose < 50 else None
543
546
  print() if verbose < 50 else None
544
547
 
545
548
  # Step 6
@@ -572,7 +575,7 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
572
575
  ) if verbose < 50 else None
573
576
  SNSTopics2 = []
574
577
  logging.warning(
575
- "Checking account %s in region %s for", fChildAccountId, f"{fRegion + Fore.RED} SNS Topics"
578
+ "Checking account %s in region %s for SNS Topics", fChildAccountId, fRegion
576
579
  )
577
580
  print(
578
581
  ERASE_LINE, f"Checking account {fChildAccountId} in region {fRegion} for SNS Topics", end="\r"
@@ -595,18 +598,18 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
595
598
  ProcessStatus[Step]["Success"] = False
596
599
 
597
600
  if ProcessStatus[Step]["Success"]:
598
- print(f"{ERASE_LINE + Fore.GREEN}** {Step} completed with no issues") if verbose < 50 else None
601
+ print(f"{ERASE_LINE}** {Step} completed with no issues") if verbose < 50 else None
599
602
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
600
603
  print(
601
- f"{ERASE_LINE + Fore.GREEN}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but we were able to remove the offending SNS Topics"
604
+ f"{ERASE_LINE}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but we were able to remove the offending SNS Topics"
602
605
  ) if verbose < 50 else None
603
606
  ProcessStatus[Step]["Success"] = True
604
607
  elif ProcessStatus[Step]["IssuesFound"] > ProcessStatus[Step]["IssuesFixed"]:
605
608
  print(
606
- f"{ERASE_LINE + Fore.RED}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blockers found that wasn't fixed"
609
+ f"{ERASE_LINE}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blockers found that wasn't fixed"
607
610
  ) if verbose < 50 else None
608
611
  else:
609
- print(f"{ERASE_LINE + Fore.RED}** {Step} completed with blockers found") if verbose < 50 else None
612
+ print(f"{ERASE_LINE}** {Step} completed with blockers found") if verbose < 50 else None
610
613
  print() if verbose < 50 else None
611
614
 
612
615
  # Step 8
@@ -650,18 +653,18 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
650
653
  ProcessStatus[Step]["Success"] = False
651
654
 
652
655
  if ProcessStatus[Step]["Success"]:
653
- print(f"{ERASE_LINE + Fore.GREEN}** {Step} completed with no issues") if verbose < 50 else None
656
+ print(f"{ERASE_LINE}** {Step} completed with no issues") if verbose < 50 else None
654
657
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
655
658
  print(
656
- f"{ERASE_LINE + Fore.GREEN}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but we were able to remove the offending Lambda Functions"
659
+ f"{ERASE_LINE}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but we were able to remove the offending Lambda Functions"
657
660
  ) if verbose < 50 else None
658
661
  ProcessStatus[Step]["Success"] = True
659
662
  elif ProcessStatus[Step]["IssuesFound"] > ProcessStatus[Step]["IssuesFixed"]:
660
663
  print(
661
- f"{ERASE_LINE + Fore.RED}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blockers found that wasn't fixed"
664
+ f"{ERASE_LINE}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blockers found that wasn't fixed"
662
665
  ) if verbose < 50 else None
663
666
  else:
664
- print(f"{ERASE_LINE + Fore.RED}** {Step} completed with blockers found") if verbose < 50 else None
667
+ print(f"{ERASE_LINE}** {Step} completed with blockers found") if verbose < 50 else None
665
668
  print() if verbose < 50 else None
666
669
 
667
670
  # Step 9
@@ -694,18 +697,18 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
694
697
  ProcessStatus[Step]["Success"] = False
695
698
 
696
699
  if ProcessStatus[Step]["Success"]:
697
- print(f"{ERASE_LINE + Fore.GREEN}** {Step} completed with no issues") if verbose < 50 else None
700
+ print(f"{ERASE_LINE}** {Step} completed with no issues") if verbose < 50 else None
698
701
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
699
702
  print(
700
- f"{ERASE_LINE + Fore.GREEN}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but we were able to remove the offending IAM roles"
703
+ f"{ERASE_LINE}** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but we were able to remove the offending IAM roles"
701
704
  ) if verbose < 50 else None
702
705
  ProcessStatus[Step]["Success"] = True
703
706
  elif ProcessStatus[Step]["IssuesFound"] > ProcessStatus[Step]["IssuesFixed"]:
704
707
  print(
705
- f"{ERASE_LINE + Fore.RED}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blockers found that remain to be fixed"
708
+ f"{ERASE_LINE}** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blockers found that remain to be fixed"
706
709
  ) if verbose < 50 else None
707
710
  else:
708
- print(f"{ERASE_LINE + Fore.RED}** {Step} completed with blockers found") if verbose < 50 else None
711
+ print(f"{ERASE_LINE}** {Step} completed with blockers found") if verbose < 50 else None
709
712
  print() if verbose < 50 else None
710
713
 
711
714
  # Step 10
@@ -741,7 +744,7 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
741
744
  ProcessStatus[Step]["Success"] = False
742
745
 
743
746
  if ProcessStatus[Step]["Success"]:
744
- print(f"{ERASE_LINE + Fore.GREEN}** {Step} completed with no issues") if verbose < 50 else None
747
+ print(f"{ERASE_LINE}** {Step} completed with no issues") if verbose < 50 else None
745
748
  elif ProcessStatus[Step]["IssuesFound"] - ProcessStatus[Step]["IssuesFixed"] == 0:
746
749
  print(
747
750
  f"{ERASE_LINE}[green]** {Step} found {ProcessStatus[Step]['IssuesFound']} issues, but we were able to remove the offending CW Log groups"
@@ -752,7 +755,7 @@ def DoAccountSteps(fChildAccountId, aws_account, fFixRun, fRegion):
752
755
  f"{ERASE_LINE}[red]** {Step} completed, but there were {ProcessStatus[Step]['IssuesFound'] - ProcessStatus[Step]['IssuesFixed']} blockers found that remain to be fixed "
753
756
  ) if verbose < 50 else None
754
757
  else:
755
- print(f"{ERASE_LINE + Fore.RED}** {Step} completed with blockers found") if verbose < 50 else None
758
+ print(f"{ERASE_LINE}** {Step} completed with blockers found") if verbose < 50 else None
756
759
  print() if verbose < 50 else None
757
760
 
758
761
  """ Function Summary """
@@ -977,7 +980,7 @@ def display_results():
977
980
  )
978
981
  for step in account:
979
982
  if step[:4] == "Step" and len(account[step]["ProblemsFound"]) > 0:
980
- print(f"{Fore.LIGHTRED_EX}Issues Found for {step} in account {account['AccountId']}:")
983
+ print(f"[red]Issues Found for {step} in account {account['AccountId']}:[/red]")
981
984
  pprint(account[step]["ProblemsFound"])
982
985
 
983
986
 
@@ -3,15 +3,19 @@
3
3
  import logging
4
4
  import sys
5
5
 
6
- import ec2_vpc_utils as vpc_modules
7
- import Inventory_Modules
8
- from account_class import aws_acct_access
9
- from ArgumentsClass import CommonArguments
6
+ from runbooks.inventory import ec2_vpc_utils as vpc_modules
7
+ from runbooks.inventory import inventory_modules as Inventory_Modules
8
+ from runbooks.inventory.account_class import aws_acct_access
9
+ from runbooks.inventory.ArgumentsClass import CommonArguments
10
10
  from botocore.exceptions import ClientError
11
11
  from runbooks.common.rich_utils import console, print_success, print_error, print_info
12
12
  from runbooks.common.rich_utils import console, create_table
13
+ from runbooks import __version__
13
14
 
14
- __version__ = "2023.05.04"
15
+
16
+
17
+ # Terminal control constants
18
+ ERASE_LINE = '\x1b[2K'
15
19
 
16
20
  parser = CommonArguments()
17
21
  parser.singleprofile()
@@ -222,11 +226,11 @@ if aws_account.AccountType.lower() == "root" and pChildAccountId is None:
222
226
  )
223
227
  elif pChildAccountId is None:
224
228
  sys.exit(
225
- f"Account {aws_account.acct_number} is a {aws_account.AccountType} account. This script should be run with Management Account credentials."
229
+ f"Account {aws_account.acct_num} is a {aws_account.AccountType} account. This script should be run with Management Account credentials."
226
230
  )
227
231
  else:
228
232
  print(
229
- f"Account {aws_account.acct_number} is a {aws_account.AccountType} account."
233
+ f"Account {aws_account.acct_num} is a {aws_account.AccountType} account."
230
234
  f"We're checking to validate that account {pChildAccountId} can be adopted into the Landing Zone"
231
235
  )
232
236
  ChildAccountList = [pChildAccountId]
@@ -285,7 +289,7 @@ for childaccount in ChildAccountList:
285
289
  continue
286
290
  else:
287
291
  logging.error(
288
- f"Was able to successfully connect to account {childaccount} using credentials from account {aws_account.acct_number}... "
292
+ f"Was able to successfully connect to account {childaccount} using credentials from account {aws_account.acct_num}... "
289
293
  )
290
294
  print()
291
295
  print(f"[green]** Step 0 completed without issues")
@@ -362,18 +366,18 @@ for childaccount in ChildAccountList:
362
366
 
363
367
  print()
364
368
  if ProcessStatus[childaccount]["Step1"]["Success"]:
365
- print(f"{ERASE_LINE + Fore.GREEN}** Step 1 completed with no issues")
369
+ print(f"{ERASE_LINE}** Step 1 completed with no issues")
366
370
  elif ProcessStatus[childaccount]["Step1"]["IssuesFound"] - ProcessStatus[childaccount]["Step1"]["IssuesFixed"] == 0:
367
371
  print(
368
- f"{ERASE_LINE + Fore.GREEN}** Step 1 found {ProcessStatus[childaccount]['Step1']['IssuesFound']} issues, but they were fixed by deleting the default vpcs"
372
+ f"{ERASE_LINE}** Step 1 found {ProcessStatus[childaccount]['Step1']['IssuesFound']} issues, but they were fixed by deleting the default vpcs"
369
373
  )
370
374
  ProcessStatus[childaccount]["Step1"]["Success"] = True
371
375
  elif ProcessStatus[childaccount]["Step1"]["IssuesFound"] > ProcessStatus[childaccount]["Step1"]["IssuesFixed"]:
372
376
  print(
373
- f"{ERASE_LINE + Fore.RED}** Step 1 completed, but there were {ProcessStatus[childaccount]['Step1']['IssuesFound'] - ProcessStatus[childaccount]['Step1']['IssuesFixed']} vpcs that couldn't be fixed"
377
+ f"{ERASE_LINE}** Step 1 completed, but there were {ProcessStatus[childaccount]['Step1']['IssuesFound'] - ProcessStatus[childaccount]['Step1']['IssuesFixed']} vpcs that couldn't be fixed"
374
378
  )
375
379
  else:
376
- print(f"{ERASE_LINE + Fore.RED}** Step 1 completed with blockers found")
380
+ print(f"{ERASE_LINE}** Step 1 completed with blockers found")
377
381
 
378
382
  # Step 2
379
383
  # This part will check the Config Recorder and Delivery Channel. If they have one, we need to delete it, so we can create another. We'll ask whether this is ok before we delete.
@@ -422,7 +426,7 @@ for childaccount in ChildAccountList:
422
426
  logging.error(
423
427
  f"[red]Found a config recorder for account %s in region %s",
424
428
  ConfigList[i]["AccountID"],
425
- ConfigList[i]["Region"] + Fore.RESET,
429
+ ConfigList[i]["Region"],
426
430
  )
427
431
  ProcessStatus[childaccount]["Step2"]["IssuesFound"] += 1
428
432
  config_deliv_channels_found = True
@@ -442,7 +446,7 @@ for childaccount in ChildAccountList:
442
446
  logging.error(
443
447
  f"[red]I found a delivery channel for account %s in region %s",
444
448
  DeliveryChanList[i]["AccountID"],
445
- DeliveryChanList[i]["Region"] + Fore.RESET,
449
+ DeliveryChanList[i]["Region"],
446
450
  )
447
451
  ProcessStatus[childaccount]["Step2"]["IssuesFound"] += 1
448
452
  config_deliv_channels_found = True
@@ -464,18 +468,18 @@ for childaccount in ChildAccountList:
464
468
  ProcessStatus[childaccount]["Step2"]["Success"] = True
465
469
 
466
470
  if ProcessStatus[childaccount]["Step2"]["Success"]:
467
- print(f"{ERASE_LINE + Fore.GREEN}** Step 2 completed with no issues")
471
+ print(f"{ERASE_LINE}** Step 2 completed with no issues")
468
472
  elif ProcessStatus[childaccount]["Step2"]["IssuesFound"] - ProcessStatus[childaccount]["Step2"]["IssuesFixed"] == 0:
469
473
  print(
470
- f"{ERASE_LINE + Fore.GREEN}** Step 2 found {ProcessStatus[childaccount]['Step2']['IssuesFound']} issues, but they were fixed by deleting the existing Config Recorders and Delivery Channels"
474
+ f"{ERASE_LINE}** Step 2 found {ProcessStatus[childaccount]['Step2']['IssuesFound']} issues, but they were fixed by deleting the existing Config Recorders and Delivery Channels"
471
475
  )
472
476
  ProcessStatus[childaccount]["Step2"]["Success"] = True
473
477
  elif ProcessStatus[childaccount]["Step2"]["IssuesFound"] > ProcessStatus[childaccount]["Step2"]["IssuesFixed"]:
474
478
  print(
475
- f"{ERASE_LINE + Fore.RED}** Step 2 completed, but there were {ProcessStatus[childaccount]['Step2']['IssuesFound'] - ProcessStatus[childaccount]['Step2']['IssuesFixed']} items found that couldn't be deleted"
479
+ f"{ERASE_LINE}** Step 2 completed, but there were {ProcessStatus[childaccount]['Step2']['IssuesFound'] - ProcessStatus[childaccount]['Step2']['IssuesFixed']} items found that couldn't be deleted"
476
480
  )
477
481
  else:
478
- print(f"{ERASE_LINE + Fore.RED}** Step 2 completed with blockers found")
482
+ print(f"{ERASE_LINE}** Step 2 completed with blockers found")
479
483
  print()
480
484
 
481
485
  # Step 3
@@ -521,18 +525,18 @@ for childaccount in ChildAccountList:
521
525
  ProcessStatus[childaccount]["Step3"]["Success"] = True
522
526
 
523
527
  if ProcessStatus[childaccount]["Step3"]["Success"]:
524
- print(f"{ERASE_LINE + Fore.GREEN}** Step 3 completed with no issues")
528
+ print(f"{ERASE_LINE}** Step 3 completed with no issues")
525
529
  elif ProcessStatus[childaccount]["Step3"]["IssuesFound"] - ProcessStatus[childaccount]["Step3"]["IssuesFixed"] == 0:
526
530
  print(
527
- f"{ERASE_LINE + Fore.GREEN}** Step 3 found {ProcessStatus[childaccount]['Step3']['IssuesFound']} issues, but they were fixed by deleting the existing CloudTrail trail names"
531
+ f"{ERASE_LINE}** Step 3 found {ProcessStatus[childaccount]['Step3']['IssuesFound']} issues, but they were fixed by deleting the existing CloudTrail trail names"
528
532
  )
529
533
  ProcessStatus[childaccount]["Step3"]["Success"] = True
530
534
  elif ProcessStatus[childaccount]["Step3"]["IssuesFound"] > ProcessStatus[childaccount]["Step3"]["IssuesFixed"]:
531
535
  print(
532
- f"{ERASE_LINE + Fore.RED}** Step 3 completed, but there were {ProcessStatus[childaccount]['Step3']['IssuesFound'] - ProcessStatus[childaccount]['Step3']['IssuesFixed']} trail names found that couldn't be deleted"
536
+ f"{ERASE_LINE}** Step 3 completed, but there were {ProcessStatus[childaccount]['Step3']['IssuesFound'] - ProcessStatus[childaccount]['Step3']['IssuesFixed']} trail names found that couldn't be deleted"
533
537
  )
534
538
  else:
535
- print(f"{ERASE_LINE + Fore.RED}** Step 3 completed with blockers found")
539
+ print(f"{ERASE_LINE}** Step 3 completed with blockers found")
536
540
  print()
537
541
 
538
542
  # Step 4
@@ -571,7 +575,7 @@ for childaccount in ChildAccountList:
571
575
  f"[red]I found a GuardDuty invitation for account %s in region %s from account %s ",
572
576
  childaccount,
573
577
  GDinvites2[i]["Region"],
574
- GDinvites2[i]["AccountId"] + Fore.RESET,
578
+ GDinvites2[i]["AccountId"],
575
579
  )
576
580
  ProcessStatus[childaccount]["Step4"]["IssuesFound"] += 1
577
581
  if FixRun:
@@ -591,18 +595,18 @@ for childaccount in ChildAccountList:
591
595
  ProcessStatus[childaccount]["Step4"]["Success"] = True
592
596
 
593
597
  if ProcessStatus[childaccount]["Step4"]["Success"]:
594
- print(f"{ERASE_LINE + Fore.GREEN}** Step 4 completed with no issues")
598
+ print(f"{ERASE_LINE}** Step 4 completed with no issues")
595
599
  elif ProcessStatus[childaccount]["Step4"]["IssuesFound"] - ProcessStatus[childaccount]["Step4"]["IssuesFixed"] == 0:
596
600
  print(
597
- f"{ERASE_LINE + Fore.GREEN}** Step 4 found {ProcessStatus[childaccount]['Step4']['IssuesFound']} guardduty invites, but they were deleted"
601
+ f"{ERASE_LINE}** Step 4 found {ProcessStatus[childaccount]['Step4']['IssuesFound']} guardduty invites, but they were deleted"
598
602
  )
599
603
  ProcessStatus[childaccount]["Step4"]["Success"] = True
600
604
  elif ProcessStatus[childaccount]["Step4"]["IssuesFound"] > ProcessStatus[childaccount]["Step4"]["IssuesFixed"]:
601
605
  print(
602
- f"{ERASE_LINE + Fore.RED}** Step 4 completed, but there were {ProcessStatus[childaccount]['Step4']['IssuesFound'] - ProcessStatus[childaccount]['Step4']['IssuesFixed']} guardduty invites found that couldn't be deleted"
606
+ f"{ERASE_LINE}** Step 4 completed, but there were {ProcessStatus[childaccount]['Step4']['IssuesFound'] - ProcessStatus[childaccount]['Step4']['IssuesFixed']} guardduty invites found that couldn't be deleted"
603
607
  )
604
608
  else:
605
- print(f"{ERASE_LINE + Fore.RED}** Step 4 completed with blockers found")
609
+ print(f"{ERASE_LINE}** Step 4 completed with blockers found")
606
610
  print()
607
611
 
608
612
  """
@@ -629,18 +633,18 @@ for childaccount in ChildAccountList:
629
633
  ProcessStatus[childaccount]["Step5"]["IssuesFound"] += 1
630
634
 
631
635
  if ProcessStatus[childaccount]["Step5"]["Success"]:
632
- print(f"{ERASE_LINE + Fore.GREEN}** Step 5 completed with no issues")
636
+ print(f"{ERASE_LINE}** Step 5 completed with no issues")
633
637
  elif ProcessStatus[childaccount]["Step5"]["IssuesFound"] - ProcessStatus[childaccount]["Step5"]["IssuesFixed"] == 0:
634
638
  print(
635
- f"{ERASE_LINE + Fore.GREEN}** Step 5 found {ProcessStatus[childaccount]['Step5']['IssuesFound']} issues, but we were able to move the account into the they were able to be fixed"
639
+ f"{ERASE_LINE}** Step 5 found {ProcessStatus[childaccount]['Step5']['IssuesFound']} issues, but we were able to move the account into the they were able to be fixed"
636
640
  )
637
641
  ProcessStatus[childaccount]["Step5"]["Success"] = True
638
642
  elif ProcessStatus[childaccount]["Step5"]["IssuesFound"] > ProcessStatus[childaccount]["Step5"]["IssuesFixed"]:
639
643
  print(
640
- f"{ERASE_LINE + Fore.RED}** Step 5 completed, but there were {ProcessStatus[childaccount]['Step5']['IssuesFound'] - ProcessStatus[childaccount]['Step5']['IssuesFixed']} blockers found that couldn't be fixed"
644
+ f"{ERASE_LINE}** Step 5 completed, but there were {ProcessStatus[childaccount]['Step5']['IssuesFound'] - ProcessStatus[childaccount]['Step5']['IssuesFixed']} blockers found that couldn't be fixed"
641
645
  )
642
646
  else:
643
- print(f"{ERASE_LINE + Fore.RED}** Step 5 completed with blockers found")
647
+ print(f"{ERASE_LINE}** Step 5 completed with blockers found")
644
648
  print()
645
649
 
646
650
  print(f"[cyan]Account {childaccount} is complete. {accountsleft} more to go!!")
@@ -28,6 +28,8 @@ from botocore.exceptions import ClientError, ProfileNotFound
28
28
 
29
29
  # Import runbooks enterprise standards
30
30
  from runbooks.common.rich_utils import (
31
+
32
+ # Terminal control constants
31
33
  console,
32
34
  print_header,
33
35
  print_success,
@@ -37,9 +39,11 @@ from runbooks.common.rich_utils import (
37
39
  create_progress_bar,
38
40
  create_panel,
39
41
  )
40
- from runbooks.common.profile_utils import get_profile_for_operation
41
42
 
42
- __version__ = "1.0.0"
43
+ # Terminal control constants
44
+ ERASE_LINE = '\x1b[2K'
45
+ from runbooks.common.profile_utils import get_profile_for_operation
46
+ from runbooks import __version__
43
47
 
44
48
 
45
49
  @dataclass
@@ -368,7 +372,8 @@ Organizational Units: {len(structured_accounts)}
368
372
  Session Cache: {len(self.session_cache)} active sessions
369
373
  """
370
374
 
371
- summary_panel = create_panel(summary_text, title="Organization Summary", style="green")
375
+ from rich.panel import Panel
376
+ summary_panel = Panel(summary_text.strip(), title="[bold green]Organization Summary[/bold green]", border_style="green")
372
377
  console.print(summary_panel)
373
378
 
374
379