runbooks 1.1.4__py3-none-any.whl → 1.1.6__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.
- runbooks/__init__.py +31 -2
- runbooks/__init___optimized.py +18 -4
- runbooks/_platform/__init__.py +1 -5
- runbooks/_platform/core/runbooks_wrapper.py +141 -138
- runbooks/aws2/accuracy_validator.py +812 -0
- runbooks/base.py +7 -0
- runbooks/cfat/assessment/compliance.py +1 -1
- runbooks/cfat/assessment/runner.py +1 -0
- runbooks/cfat/cloud_foundations_assessment.py +227 -239
- runbooks/cli/__init__.py +1 -1
- runbooks/cli/commands/cfat.py +64 -23
- runbooks/cli/commands/finops.py +1005 -54
- runbooks/cli/commands/inventory.py +135 -91
- runbooks/cli/commands/operate.py +9 -36
- runbooks/cli/commands/security.py +42 -18
- runbooks/cli/commands/validation.py +432 -18
- runbooks/cli/commands/vpc.py +81 -17
- runbooks/cli/registry.py +22 -10
- runbooks/cloudops/__init__.py +20 -27
- runbooks/cloudops/base.py +96 -107
- runbooks/cloudops/cost_optimizer.py +544 -542
- runbooks/cloudops/infrastructure_optimizer.py +5 -4
- runbooks/cloudops/interfaces.py +224 -225
- runbooks/cloudops/lifecycle_manager.py +5 -4
- runbooks/cloudops/mcp_cost_validation.py +252 -235
- runbooks/cloudops/models.py +78 -53
- runbooks/cloudops/monitoring_automation.py +5 -4
- runbooks/cloudops/notebook_framework.py +177 -213
- runbooks/cloudops/security_enforcer.py +125 -159
- runbooks/common/accuracy_validator.py +17 -12
- runbooks/common/aws_pricing.py +349 -326
- runbooks/common/aws_pricing_api.py +211 -212
- runbooks/common/aws_profile_manager.py +40 -36
- runbooks/common/aws_utils.py +74 -79
- runbooks/common/business_logic.py +126 -104
- runbooks/common/cli_decorators.py +36 -60
- runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
- runbooks/common/cross_account_manager.py +197 -204
- runbooks/common/date_utils.py +27 -39
- runbooks/common/decorators.py +29 -19
- runbooks/common/dry_run_examples.py +173 -208
- runbooks/common/dry_run_framework.py +157 -155
- runbooks/common/enhanced_exception_handler.py +15 -4
- runbooks/common/enhanced_logging_example.py +50 -64
- runbooks/common/enhanced_logging_integration_example.py +65 -37
- runbooks/common/env_utils.py +16 -16
- runbooks/common/error_handling.py +40 -38
- runbooks/common/lazy_loader.py +41 -23
- runbooks/common/logging_integration_helper.py +79 -86
- runbooks/common/mcp_cost_explorer_integration.py +476 -493
- runbooks/common/mcp_integration.py +99 -79
- runbooks/common/memory_optimization.py +140 -118
- runbooks/common/module_cli_base.py +37 -58
- runbooks/common/organizations_client.py +175 -193
- runbooks/common/patterns.py +23 -25
- runbooks/common/performance_monitoring.py +67 -71
- runbooks/common/performance_optimization_engine.py +283 -274
- runbooks/common/profile_utils.py +111 -37
- runbooks/common/rich_utils.py +315 -141
- runbooks/common/sre_performance_suite.py +177 -186
- runbooks/enterprise/__init__.py +1 -1
- runbooks/enterprise/logging.py +144 -106
- runbooks/enterprise/security.py +187 -204
- runbooks/enterprise/validation.py +43 -56
- runbooks/finops/__init__.py +26 -30
- runbooks/finops/account_resolver.py +1 -1
- runbooks/finops/advanced_optimization_engine.py +980 -0
- runbooks/finops/automation_core.py +268 -231
- runbooks/finops/business_case_config.py +184 -179
- runbooks/finops/cli.py +660 -139
- runbooks/finops/commvault_ec2_analysis.py +157 -164
- runbooks/finops/compute_cost_optimizer.py +336 -320
- runbooks/finops/config.py +20 -20
- runbooks/finops/cost_optimizer.py +484 -618
- runbooks/finops/cost_processor.py +332 -214
- runbooks/finops/dashboard_runner.py +1006 -172
- runbooks/finops/ebs_cost_optimizer.py +991 -657
- runbooks/finops/elastic_ip_optimizer.py +317 -257
- runbooks/finops/enhanced_mcp_integration.py +340 -0
- runbooks/finops/enhanced_progress.py +32 -29
- runbooks/finops/enhanced_trend_visualization.py +3 -2
- runbooks/finops/enterprise_wrappers.py +223 -285
- runbooks/finops/executive_export.py +203 -160
- runbooks/finops/helpers.py +130 -288
- runbooks/finops/iam_guidance.py +1 -1
- runbooks/finops/infrastructure/__init__.py +80 -0
- runbooks/finops/infrastructure/commands.py +506 -0
- runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
- runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
- runbooks/finops/markdown_exporter.py +337 -174
- runbooks/finops/mcp_validator.py +1952 -0
- runbooks/finops/nat_gateway_optimizer.py +1512 -481
- runbooks/finops/network_cost_optimizer.py +657 -587
- runbooks/finops/notebook_utils.py +226 -188
- runbooks/finops/optimization_engine.py +1136 -0
- runbooks/finops/optimizer.py +19 -23
- runbooks/finops/rds_snapshot_optimizer.py +367 -411
- runbooks/finops/reservation_optimizer.py +427 -363
- runbooks/finops/scenario_cli_integration.py +64 -65
- runbooks/finops/scenarios.py +1277 -438
- runbooks/finops/schemas.py +218 -182
- runbooks/finops/snapshot_manager.py +2289 -0
- runbooks/finops/types.py +3 -3
- runbooks/finops/validation_framework.py +259 -265
- runbooks/finops/vpc_cleanup_exporter.py +189 -144
- runbooks/finops/vpc_cleanup_optimizer.py +591 -573
- runbooks/finops/workspaces_analyzer.py +171 -182
- runbooks/integration/__init__.py +89 -0
- runbooks/integration/mcp_integration.py +1920 -0
- runbooks/inventory/CLAUDE.md +816 -0
- runbooks/inventory/__init__.py +2 -2
- runbooks/inventory/aws_decorators.py +2 -3
- runbooks/inventory/check_cloudtrail_compliance.py +2 -4
- runbooks/inventory/check_controltower_readiness.py +152 -151
- runbooks/inventory/check_landingzone_readiness.py +85 -84
- runbooks/inventory/cloud_foundations_integration.py +144 -149
- runbooks/inventory/collectors/aws_comprehensive.py +1 -1
- runbooks/inventory/collectors/aws_networking.py +109 -99
- runbooks/inventory/collectors/base.py +4 -0
- runbooks/inventory/core/collector.py +495 -313
- runbooks/inventory/core/formatter.py +11 -0
- runbooks/inventory/draw_org_structure.py +8 -9
- runbooks/inventory/drift_detection_cli.py +69 -96
- runbooks/inventory/ec2_vpc_utils.py +2 -2
- runbooks/inventory/find_cfn_drift_detection.py +5 -7
- runbooks/inventory/find_cfn_orphaned_stacks.py +7 -9
- runbooks/inventory/find_cfn_stackset_drift.py +5 -6
- runbooks/inventory/find_ec2_security_groups.py +48 -42
- runbooks/inventory/find_landingzone_versions.py +4 -6
- runbooks/inventory/find_vpc_flow_logs.py +7 -9
- runbooks/inventory/inventory_mcp_cli.py +48 -46
- runbooks/inventory/inventory_modules.py +103 -91
- runbooks/inventory/list_cfn_stacks.py +9 -10
- runbooks/inventory/list_cfn_stackset_operation_results.py +1 -3
- runbooks/inventory/list_cfn_stackset_operations.py +79 -57
- runbooks/inventory/list_cfn_stacksets.py +8 -10
- runbooks/inventory/list_config_recorders_delivery_channels.py +49 -39
- runbooks/inventory/list_ds_directories.py +65 -53
- runbooks/inventory/list_ec2_availability_zones.py +2 -4
- runbooks/inventory/list_ec2_ebs_volumes.py +32 -35
- runbooks/inventory/list_ec2_instances.py +23 -28
- runbooks/inventory/list_ecs_clusters_and_tasks.py +26 -34
- runbooks/inventory/list_elbs_load_balancers.py +22 -20
- runbooks/inventory/list_enis_network_interfaces.py +26 -33
- runbooks/inventory/list_guardduty_detectors.py +2 -4
- runbooks/inventory/list_iam_policies.py +2 -4
- runbooks/inventory/list_iam_roles.py +5 -7
- runbooks/inventory/list_iam_saml_providers.py +4 -6
- runbooks/inventory/list_lambda_functions.py +38 -38
- runbooks/inventory/list_org_accounts.py +6 -8
- runbooks/inventory/list_org_accounts_users.py +55 -44
- runbooks/inventory/list_rds_db_instances.py +31 -33
- runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
- runbooks/inventory/list_route53_hosted_zones.py +3 -5
- runbooks/inventory/list_servicecatalog_provisioned_products.py +37 -41
- runbooks/inventory/list_sns_topics.py +2 -4
- runbooks/inventory/list_ssm_parameters.py +4 -7
- runbooks/inventory/list_vpc_subnets.py +2 -4
- runbooks/inventory/list_vpcs.py +7 -10
- runbooks/inventory/mcp_inventory_validator.py +554 -468
- runbooks/inventory/mcp_vpc_validator.py +359 -442
- runbooks/inventory/organizations_discovery.py +63 -55
- runbooks/inventory/recover_cfn_stack_ids.py +7 -8
- runbooks/inventory/requirements.txt +0 -1
- runbooks/inventory/rich_inventory_display.py +35 -34
- runbooks/inventory/run_on_multi_accounts.py +3 -5
- runbooks/inventory/unified_validation_engine.py +281 -253
- runbooks/inventory/verify_ec2_security_groups.py +1 -1
- runbooks/inventory/vpc_analyzer.py +735 -697
- runbooks/inventory/vpc_architecture_validator.py +293 -348
- runbooks/inventory/vpc_dependency_analyzer.py +384 -380
- runbooks/inventory/vpc_flow_analyzer.py +1 -1
- runbooks/main.py +49 -34
- runbooks/main_final.py +91 -60
- runbooks/main_minimal.py +22 -10
- runbooks/main_optimized.py +131 -100
- runbooks/main_ultra_minimal.py +7 -2
- runbooks/mcp/__init__.py +36 -0
- runbooks/mcp/integration.py +679 -0
- runbooks/monitoring/performance_monitor.py +9 -4
- runbooks/operate/dynamodb_operations.py +3 -1
- runbooks/operate/ec2_operations.py +145 -137
- runbooks/operate/iam_operations.py +146 -152
- runbooks/operate/networking_cost_heatmap.py +29 -8
- runbooks/operate/rds_operations.py +223 -254
- runbooks/operate/s3_operations.py +107 -118
- runbooks/operate/vpc_operations.py +646 -616
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/commons.py +10 -7
- runbooks/remediation/commvault_ec2_analysis.py +70 -66
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
- runbooks/remediation/multi_account.py +24 -21
- runbooks/remediation/rds_snapshot_list.py +86 -60
- runbooks/remediation/remediation_cli.py +92 -146
- runbooks/remediation/universal_account_discovery.py +83 -79
- runbooks/remediation/workspaces_list.py +46 -41
- runbooks/security/__init__.py +19 -0
- runbooks/security/assessment_runner.py +1150 -0
- runbooks/security/baseline_checker.py +812 -0
- runbooks/security/cloudops_automation_security_validator.py +509 -535
- runbooks/security/compliance_automation_engine.py +17 -17
- runbooks/security/config/__init__.py +2 -2
- runbooks/security/config/compliance_config.py +50 -50
- runbooks/security/config_template_generator.py +63 -76
- runbooks/security/enterprise_security_framework.py +1 -1
- runbooks/security/executive_security_dashboard.py +519 -508
- runbooks/security/multi_account_security_controls.py +959 -1210
- runbooks/security/real_time_security_monitor.py +422 -444
- runbooks/security/security_baseline_tester.py +1 -1
- runbooks/security/security_cli.py +143 -112
- runbooks/security/test_2way_validation.py +439 -0
- runbooks/security/two_way_validation_framework.py +852 -0
- runbooks/sre/production_monitoring_framework.py +167 -177
- runbooks/tdd/__init__.py +15 -0
- runbooks/tdd/cli.py +1071 -0
- runbooks/utils/__init__.py +14 -17
- runbooks/utils/logger.py +7 -2
- runbooks/utils/version_validator.py +50 -47
- runbooks/validation/__init__.py +6 -6
- runbooks/validation/cli.py +9 -3
- runbooks/validation/comprehensive_2way_validator.py +745 -704
- runbooks/validation/mcp_validator.py +906 -228
- runbooks/validation/terraform_citations_validator.py +104 -115
- runbooks/validation/terraform_drift_detector.py +461 -454
- runbooks/vpc/README.md +617 -0
- runbooks/vpc/__init__.py +8 -1
- runbooks/vpc/analyzer.py +577 -0
- runbooks/vpc/cleanup_wrapper.py +476 -413
- runbooks/vpc/cli_cloudtrail_commands.py +339 -0
- runbooks/vpc/cli_mcp_validation_commands.py +480 -0
- runbooks/vpc/cloudtrail_audit_integration.py +717 -0
- runbooks/vpc/config.py +92 -97
- runbooks/vpc/cost_engine.py +411 -148
- runbooks/vpc/cost_explorer_integration.py +553 -0
- runbooks/vpc/cross_account_session.py +101 -106
- runbooks/vpc/enhanced_mcp_validation.py +917 -0
- runbooks/vpc/eni_gate_validator.py +961 -0
- runbooks/vpc/heatmap_engine.py +185 -160
- runbooks/vpc/mcp_no_eni_validator.py +680 -639
- runbooks/vpc/nat_gateway_optimizer.py +358 -0
- runbooks/vpc/networking_wrapper.py +15 -8
- runbooks/vpc/pdca_remediation_planner.py +528 -0
- runbooks/vpc/performance_optimized_analyzer.py +219 -231
- runbooks/vpc/runbooks_adapter.py +1167 -241
- runbooks/vpc/tdd_red_phase_stubs.py +601 -0
- runbooks/vpc/test_data_loader.py +358 -0
- runbooks/vpc/tests/conftest.py +314 -4
- runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
- runbooks/vpc/tests/test_cost_engine.py +0 -2
- runbooks/vpc/topology_generator.py +326 -0
- runbooks/vpc/unified_scenarios.py +1297 -1124
- runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
- runbooks-1.1.6.dist-info/METADATA +327 -0
- runbooks-1.1.6.dist-info/RECORD +489 -0
- runbooks/finops/README.md +0 -414
- runbooks/finops/accuracy_cross_validator.py +0 -647
- runbooks/finops/business_cases.py +0 -950
- runbooks/finops/dashboard_router.py +0 -922
- runbooks/finops/ebs_optimizer.py +0 -973
- runbooks/finops/embedded_mcp_validator.py +0 -1629
- runbooks/finops/enhanced_dashboard_runner.py +0 -527
- runbooks/finops/finops_dashboard.py +0 -584
- runbooks/finops/finops_scenarios.py +0 -1218
- runbooks/finops/legacy_migration.py +0 -730
- runbooks/finops/multi_dashboard.py +0 -1519
- runbooks/finops/single_dashboard.py +0 -1113
- runbooks/finops/unlimited_scenarios.py +0 -393
- runbooks-1.1.4.dist-info/METADATA +0 -800
- runbooks-1.1.4.dist-info/RECORD +0 -468
- {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/WHEEL +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/entry_points.txt +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/licenses/LICENSE +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/top_level.txt +0 -0
@@ -27,7 +27,7 @@ from runbooks.common.dry_run_framework import (
|
|
27
27
|
resource_creation_operation,
|
28
28
|
resource_deletion_operation,
|
29
29
|
remediation_operation,
|
30
|
-
framework
|
30
|
+
framework,
|
31
31
|
)
|
32
32
|
from runbooks.common.rich_utils import console, print_success, print_warning, print_error
|
33
33
|
|
@@ -36,64 +36,65 @@ from runbooks.common.rich_utils import console, print_success, print_warning, pr
|
|
36
36
|
# 1. DISCOVERY OPERATIONS (inventory, scan modules)
|
37
37
|
# =============================================================================
|
38
38
|
|
39
|
+
|
39
40
|
@discovery_operation
|
40
41
|
def collect_ec2_instances(
|
41
|
-
dry_run_context: DryRunContext,
|
42
|
-
profile: Optional[str] = None,
|
43
|
-
regions: Optional[List[str]] = None
|
42
|
+
dry_run_context: DryRunContext, profile: Optional[str] = None, regions: Optional[List[str]] = None
|
44
43
|
) -> Dict[str, Any]:
|
45
44
|
"""
|
46
45
|
Example discovery operation - EC2 instance collection.
|
47
|
-
|
46
|
+
|
48
47
|
Discovery operations are inherently safe, so dry-run simulates API calls
|
49
48
|
for testing purposes only.
|
50
49
|
"""
|
51
50
|
if dry_run_context.enabled:
|
52
51
|
# Simulation mode - no real API calls
|
53
52
|
console.print("[dim]🔄 Simulating EC2 instance discovery...[/dim]")
|
54
|
-
|
53
|
+
|
55
54
|
# Return simulated data
|
56
55
|
return {
|
57
56
|
"instances": [
|
58
57
|
{"id": "i-sim123", "type": "t3.micro", "state": "running"},
|
59
|
-
{"id": "i-sim456", "type": "m5.large", "state": "stopped"}
|
58
|
+
{"id": "i-sim456", "type": "m5.large", "state": "stopped"},
|
60
59
|
],
|
61
60
|
"simulated": True,
|
62
61
|
"region_count": len(regions or ["us-east-1"]),
|
63
|
-
"total_discovered": 2
|
62
|
+
"total_discovered": 2,
|
64
63
|
}
|
65
|
-
|
64
|
+
|
66
65
|
else:
|
67
66
|
# Real discovery operation
|
68
67
|
console.print("[cyan]🔍 Discovering EC2 instances across regions...[/cyan]")
|
69
|
-
|
68
|
+
|
70
69
|
session = boto3.Session(profile_name=profile)
|
71
70
|
instances = []
|
72
|
-
|
71
|
+
|
73
72
|
for region in regions or ["us-east-1"]:
|
74
73
|
try:
|
75
|
-
ec2 = session.client(
|
74
|
+
ec2 = session.client("ec2", region_name=region)
|
76
75
|
response = ec2.describe_instances()
|
77
|
-
|
78
|
-
for reservation in response[
|
79
|
-
for instance in reservation[
|
80
|
-
instances.append(
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
76
|
+
|
77
|
+
for reservation in response["Reservations"]:
|
78
|
+
for instance in reservation["Instances"]:
|
79
|
+
instances.append(
|
80
|
+
{
|
81
|
+
"id": instance["InstanceId"],
|
82
|
+
"type": instance["InstanceType"],
|
83
|
+
"state": instance["State"]["Name"],
|
84
|
+
"region": region,
|
85
|
+
}
|
86
|
+
)
|
87
|
+
|
87
88
|
except ClientError as e:
|
88
89
|
print_warning(f"Could not access region {region}: {e}")
|
89
|
-
|
90
|
+
|
90
91
|
print_success(f"Discovered {len(instances)} EC2 instances")
|
91
|
-
|
92
|
+
|
92
93
|
return {
|
93
94
|
"instances": instances,
|
94
95
|
"simulated": False,
|
95
96
|
"region_count": len(regions or ["us-east-1"]),
|
96
|
-
"total_discovered": len(instances)
|
97
|
+
"total_discovered": len(instances),
|
97
98
|
}
|
98
99
|
|
99
100
|
|
@@ -101,15 +102,14 @@ def collect_ec2_instances(
|
|
101
102
|
# 2. ANALYSIS OPERATIONS (finops, security assess, vpc analyze modules)
|
102
103
|
# =============================================================================
|
103
104
|
|
105
|
+
|
104
106
|
@analysis_operation
|
105
107
|
def analyze_cost_optimization(
|
106
|
-
dry_run_context: DryRunContext,
|
107
|
-
profile: Optional[str] = None,
|
108
|
-
account_id: Optional[str] = None
|
108
|
+
dry_run_context: DryRunContext, profile: Optional[str] = None, account_id: Optional[str] = None
|
109
109
|
) -> Dict[str, Any]:
|
110
110
|
"""
|
111
111
|
Example analysis operation - cost optimization analysis.
|
112
|
-
|
112
|
+
|
113
113
|
Analysis operations are read-only, so dry-run shows what would be analyzed
|
114
114
|
without making API calls.
|
115
115
|
"""
|
@@ -119,35 +119,31 @@ def analyze_cost_optimization(
|
|
119
119
|
console.print(f"[dim] • Account: {account_id or 'Current account'}[/dim]")
|
120
120
|
console.print(f"[dim] • Services: EC2, RDS, S3, Lambda[/dim]")
|
121
121
|
console.print(f"[dim] • Time range: Last 30 days[/dim]")
|
122
|
-
|
122
|
+
|
123
123
|
return {
|
124
124
|
"preview": True,
|
125
|
-
"scope": {
|
126
|
-
"account_id": account_id,
|
127
|
-
"services": ["EC2", "RDS", "S3", "Lambda"],
|
128
|
-
"time_range": "30 days"
|
129
|
-
}
|
125
|
+
"scope": {"account_id": account_id, "services": ["EC2", "RDS", "S3", "Lambda"], "time_range": "30 days"},
|
130
126
|
}
|
131
|
-
|
127
|
+
|
132
128
|
else:
|
133
129
|
# Real cost analysis
|
134
130
|
console.print("[green]💰 Analyzing cost optimization opportunities...[/green]")
|
135
|
-
|
131
|
+
|
136
132
|
session = boto3.Session(profile_name=profile)
|
137
|
-
cost_explorer = session.client(
|
138
|
-
|
133
|
+
cost_explorer = session.client("ce")
|
134
|
+
|
139
135
|
# Real cost analysis logic here
|
140
136
|
# This is a simplified example
|
141
|
-
|
137
|
+
|
142
138
|
print_success("Cost analysis completed")
|
143
|
-
|
139
|
+
|
144
140
|
return {
|
145
141
|
"analysis_complete": True,
|
146
142
|
"recommendations": [
|
147
143
|
{"service": "EC2", "potential_savings": "$150/month"},
|
148
|
-
{"service": "RDS", "potential_savings": "$75/month"}
|
144
|
+
{"service": "RDS", "potential_savings": "$75/month"},
|
149
145
|
],
|
150
|
-
"total_potential_savings": "$225/month"
|
146
|
+
"total_potential_savings": "$225/month",
|
151
147
|
}
|
152
148
|
|
153
149
|
|
@@ -155,51 +151,46 @@ def analyze_cost_optimization(
|
|
155
151
|
# 3. ASSESSMENT OPERATIONS (cfat assess module)
|
156
152
|
# =============================================================================
|
157
153
|
|
154
|
+
|
158
155
|
@assessment_operation
|
159
156
|
def assess_security_compliance(
|
160
|
-
dry_run_context: DryRunContext,
|
161
|
-
profile: Optional[str] = None,
|
162
|
-
frameworks: Optional[List[str]] = None
|
157
|
+
dry_run_context: DryRunContext, profile: Optional[str] = None, frameworks: Optional[List[str]] = None
|
163
158
|
) -> Dict[str, Any]:
|
164
159
|
"""
|
165
160
|
Example assessment operation - security compliance assessment.
|
166
|
-
|
161
|
+
|
167
162
|
Assessment operations are read-only, so dry-run shows assessment scope.
|
168
163
|
"""
|
169
164
|
frameworks = frameworks or ["SOC2", "PCI-DSS", "HIPAA"]
|
170
|
-
|
165
|
+
|
171
166
|
if dry_run_context.enabled:
|
172
167
|
# Preview mode - show assessment scope
|
173
168
|
console.print("[dim]🔍 Preview: Security assessment scope[/dim]")
|
174
169
|
console.print(f"[dim] • Frameworks: {', '.join(frameworks)}[/dim]")
|
175
170
|
console.print(f"[dim] • Services to check: IAM, S3, EC2, VPC[/dim]")
|
176
171
|
console.print(f"[dim] • Estimated duration: 5-10 minutes[/dim]")
|
177
|
-
|
178
|
-
return {
|
179
|
-
|
180
|
-
"frameworks": frameworks,
|
181
|
-
"estimated_checks": 45
|
182
|
-
}
|
183
|
-
|
172
|
+
|
173
|
+
return {"preview": True, "frameworks": frameworks, "estimated_checks": 45}
|
174
|
+
|
184
175
|
else:
|
185
176
|
# Real security assessment
|
186
177
|
console.print("[blue]🔒 Conducting security compliance assessment...[/blue]")
|
187
|
-
|
178
|
+
|
188
179
|
session = boto3.Session(profile_name=profile)
|
189
|
-
|
180
|
+
|
190
181
|
# Real assessment logic here
|
191
182
|
# This is a simplified example
|
192
|
-
|
183
|
+
|
193
184
|
results = {
|
194
185
|
"frameworks_assessed": frameworks,
|
195
186
|
"total_checks": 45,
|
196
187
|
"passed": 38,
|
197
188
|
"failed": 7,
|
198
|
-
"compliance_score": "84.4%"
|
189
|
+
"compliance_score": "84.4%",
|
199
190
|
}
|
200
|
-
|
191
|
+
|
201
192
|
print_success(f"Assessment completed - Compliance score: {results['compliance_score']}")
|
202
|
-
|
193
|
+
|
203
194
|
return results
|
204
195
|
|
205
196
|
|
@@ -207,16 +198,17 @@ def assess_security_compliance(
|
|
207
198
|
# 4. RESOURCE CREATION OPERATIONS (operate module)
|
208
199
|
# =============================================================================
|
209
200
|
|
201
|
+
|
210
202
|
@resource_creation_operation(estimated_impact="Create 1 EC2 instance (~$25/month)")
|
211
203
|
def create_ec2_instance(
|
212
204
|
dry_run_context: DryRunContext,
|
213
205
|
instance_type: str = "t3.micro",
|
214
206
|
image_id: Optional[str] = None,
|
215
|
-
profile: Optional[str] = None
|
207
|
+
profile: Optional[str] = None,
|
216
208
|
) -> Dict[str, Any]:
|
217
209
|
"""
|
218
210
|
Example resource creation operation - EC2 instance creation.
|
219
|
-
|
211
|
+
|
220
212
|
Resource creation operations default to dry-run for safety.
|
221
213
|
"""
|
222
214
|
if dry_run_context.enabled:
|
@@ -225,35 +217,30 @@ def create_ec2_instance(
|
|
225
217
|
console.print(f"[dim] • Instance type: {instance_type}[/dim]")
|
226
218
|
console.print(f"[dim] • AMI ID: {image_id or 'Latest Amazon Linux 2'}[/dim]")
|
227
219
|
console.print(f"[dim] • Estimated cost: ~$25/month[/dim]")
|
228
|
-
|
229
|
-
return {
|
230
|
-
|
231
|
-
"instance_type": instance_type,
|
232
|
-
"image_id": image_id,
|
233
|
-
"estimated_monthly_cost": 25.00
|
234
|
-
}
|
235
|
-
|
220
|
+
|
221
|
+
return {"preview": True, "instance_type": instance_type, "image_id": image_id, "estimated_monthly_cost": 25.00}
|
222
|
+
|
236
223
|
else:
|
237
224
|
# Real instance creation
|
238
225
|
console.print("[green]🚀 Creating EC2 instance...[/green]")
|
239
|
-
|
226
|
+
|
240
227
|
session = boto3.Session(profile_name=profile)
|
241
|
-
ec2 = session.client(
|
242
|
-
|
228
|
+
ec2 = session.client("ec2")
|
229
|
+
|
243
230
|
# Use default AMI if not specified
|
244
231
|
if not image_id:
|
245
232
|
# Get latest Amazon Linux 2 AMI
|
246
233
|
images = ec2.describe_images(
|
247
|
-
Owners=[
|
234
|
+
Owners=["amazon"],
|
248
235
|
Filters=[
|
249
|
-
{
|
250
|
-
{
|
251
|
-
{
|
252
|
-
]
|
236
|
+
{"Name": "name", "Values": ["amzn2-ami-hvm-*"]},
|
237
|
+
{"Name": "architecture", "Values": ["x86_64"]},
|
238
|
+
{"Name": "virtualization-type", "Values": ["hvm"]},
|
239
|
+
],
|
253
240
|
)
|
254
|
-
if images[
|
255
|
-
image_id = sorted(images[
|
256
|
-
|
241
|
+
if images["Images"]:
|
242
|
+
image_id = sorted(images["Images"], key=lambda x: x["CreationDate"], reverse=True)[0]["ImageId"]
|
243
|
+
|
257
244
|
try:
|
258
245
|
response = ec2.run_instances(
|
259
246
|
ImageId=image_id,
|
@@ -262,25 +249,20 @@ def create_ec2_instance(
|
|
262
249
|
InstanceType=instance_type,
|
263
250
|
TagSpecifications=[
|
264
251
|
{
|
265
|
-
|
266
|
-
|
267
|
-
{
|
268
|
-
{
|
269
|
-
]
|
252
|
+
"ResourceType": "instance",
|
253
|
+
"Tags": [
|
254
|
+
{"Key": "CreatedBy", "Value": "CloudOps-Runbooks"},
|
255
|
+
{"Key": "Purpose", "Value": "Testing"},
|
256
|
+
],
|
270
257
|
}
|
271
|
-
]
|
258
|
+
],
|
272
259
|
)
|
273
|
-
|
274
|
-
instance_id = response[
|
260
|
+
|
261
|
+
instance_id = response["Instances"][0]["InstanceId"]
|
275
262
|
print_success(f"EC2 instance created: {instance_id}")
|
276
|
-
|
277
|
-
return {
|
278
|
-
|
279
|
-
"instance_type": instance_type,
|
280
|
-
"image_id": image_id,
|
281
|
-
"created": True
|
282
|
-
}
|
283
|
-
|
263
|
+
|
264
|
+
return {"instance_id": instance_id, "instance_type": instance_type, "image_id": image_id, "created": True}
|
265
|
+
|
284
266
|
except ClientError as e:
|
285
267
|
print_error(f"Failed to create instance: {e}")
|
286
268
|
raise
|
@@ -290,15 +272,14 @@ def create_ec2_instance(
|
|
290
272
|
# 5. RESOURCE DELETION OPERATIONS (operate module)
|
291
273
|
# =============================================================================
|
292
274
|
|
275
|
+
|
293
276
|
@resource_deletion_operation(estimated_impact="Delete EC2 instances (~$150/month savings)")
|
294
277
|
def terminate_ec2_instances(
|
295
|
-
dry_run_context: DryRunContext,
|
296
|
-
instance_ids: List[str],
|
297
|
-
profile: Optional[str] = None
|
278
|
+
dry_run_context: DryRunContext, instance_ids: List[str], profile: Optional[str] = None
|
298
279
|
) -> Dict[str, Any]:
|
299
280
|
"""
|
300
281
|
Example resource deletion operation - EC2 instance termination.
|
301
|
-
|
282
|
+
|
302
283
|
Resource deletion operations default to dry-run and require confirmation.
|
303
284
|
"""
|
304
285
|
if dry_run_context.enabled:
|
@@ -308,40 +289,38 @@ def terminate_ec2_instances(
|
|
308
289
|
console.print(f"[dim] • Instance IDs: {', '.join(instance_ids)}[/dim]")
|
309
290
|
console.print(f"[dim] • Estimated savings: ~$150/month[/dim]")
|
310
291
|
console.print(f"[dim] • ⚠️ THIS OPERATION IS IRREVERSIBLE[/dim]")
|
311
|
-
|
292
|
+
|
312
293
|
return {
|
313
294
|
"preview": True,
|
314
295
|
"instances_to_terminate": instance_ids,
|
315
296
|
"estimated_savings": 150.00,
|
316
|
-
"irreversible": True
|
297
|
+
"irreversible": True,
|
317
298
|
}
|
318
|
-
|
299
|
+
|
319
300
|
else:
|
320
301
|
# Real instance termination
|
321
302
|
console.print("[red]💥 Terminating EC2 instances...[/red]")
|
322
|
-
|
303
|
+
|
323
304
|
session = boto3.Session(profile_name=profile)
|
324
|
-
ec2 = session.client(
|
325
|
-
|
305
|
+
ec2 = session.client("ec2")
|
306
|
+
|
326
307
|
try:
|
327
308
|
response = ec2.terminate_instances(InstanceIds=instance_ids)
|
328
|
-
|
309
|
+
|
329
310
|
terminated = []
|
330
|
-
for instance in response[
|
331
|
-
terminated.append(
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
311
|
+
for instance in response["TerminatingInstances"]:
|
312
|
+
terminated.append(
|
313
|
+
{
|
314
|
+
"instance_id": instance["InstanceId"],
|
315
|
+
"current_state": instance["CurrentState"]["Name"],
|
316
|
+
"previous_state": instance["PreviousState"]["Name"],
|
317
|
+
}
|
318
|
+
)
|
319
|
+
|
337
320
|
print_success(f"Successfully initiated termination of {len(terminated)} instances")
|
338
|
-
|
339
|
-
return {
|
340
|
-
|
341
|
-
"count": len(terminated),
|
342
|
-
"operation": "terminate"
|
343
|
-
}
|
344
|
-
|
321
|
+
|
322
|
+
return {"terminated_instances": terminated, "count": len(terminated), "operation": "terminate"}
|
323
|
+
|
345
324
|
except ClientError as e:
|
346
325
|
print_error(f"Failed to terminate instances: {e}")
|
347
326
|
raise
|
@@ -351,15 +330,14 @@ def terminate_ec2_instances(
|
|
351
330
|
# 6. SECURITY REMEDIATION OPERATIONS (remediation module)
|
352
331
|
# =============================================================================
|
353
332
|
|
333
|
+
|
354
334
|
@remediation_operation(estimated_impact="Fix S3 public buckets (security improvement)")
|
355
335
|
def fix_public_s3_buckets(
|
356
|
-
dry_run_context: DryRunContext,
|
357
|
-
bucket_names: List[str],
|
358
|
-
profile: Optional[str] = None
|
336
|
+
dry_run_context: DryRunContext, bucket_names: List[str], profile: Optional[str] = None
|
359
337
|
) -> Dict[str, Any]:
|
360
338
|
"""
|
361
339
|
Example security remediation operation - fix public S3 buckets.
|
362
|
-
|
340
|
+
|
363
341
|
Remediation operations default to dry-run and require confirmation.
|
364
342
|
"""
|
365
343
|
if dry_run_context.enabled:
|
@@ -368,61 +346,55 @@ def fix_public_s3_buckets(
|
|
368
346
|
console.print(f"[dim] • Buckets to secure: {len(bucket_names)}[/dim]")
|
369
347
|
console.print(f"[dim] • Bucket names: {', '.join(bucket_names)}[/dim]")
|
370
348
|
console.print(f"[dim] • Actions: Remove public access, update policies[/dim]")
|
371
|
-
|
349
|
+
|
372
350
|
return {
|
373
351
|
"preview": True,
|
374
352
|
"buckets_to_fix": bucket_names,
|
375
353
|
"remediation_actions": [
|
376
354
|
"Remove public read access",
|
377
|
-
"Remove public write access",
|
355
|
+
"Remove public write access",
|
378
356
|
"Update bucket policies",
|
379
|
-
"Enable access logging"
|
380
|
-
]
|
357
|
+
"Enable access logging",
|
358
|
+
],
|
381
359
|
}
|
382
|
-
|
360
|
+
|
383
361
|
else:
|
384
362
|
# Real security remediation
|
385
363
|
console.print("[green]🔒 Applying security remediation to S3 buckets...[/green]")
|
386
|
-
|
364
|
+
|
387
365
|
session = boto3.Session(profile_name=profile)
|
388
|
-
s3 = session.client(
|
389
|
-
|
366
|
+
s3 = session.client("s3")
|
367
|
+
|
390
368
|
remediated_buckets = []
|
391
|
-
|
369
|
+
|
392
370
|
for bucket_name in bucket_names:
|
393
371
|
try:
|
394
372
|
# Block public access
|
395
373
|
s3.put_public_access_block(
|
396
374
|
Bucket=bucket_name,
|
397
375
|
PublicAccessBlockConfiguration={
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
}
|
376
|
+
"BlockPublicAcls": True,
|
377
|
+
"IgnorePublicAcls": True,
|
378
|
+
"BlockPublicPolicy": True,
|
379
|
+
"RestrictPublicBuckets": True,
|
380
|
+
},
|
403
381
|
)
|
404
|
-
|
405
|
-
remediated_buckets.append(
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
})
|
410
|
-
|
382
|
+
|
383
|
+
remediated_buckets.append(
|
384
|
+
{"bucket_name": bucket_name, "status": "secured", "actions_applied": ["public_access_blocked"]}
|
385
|
+
)
|
386
|
+
|
411
387
|
except ClientError as e:
|
412
388
|
print_warning(f"Could not secure bucket {bucket_name}: {e}")
|
413
|
-
remediated_buckets.append({
|
414
|
-
|
415
|
-
|
416
|
-
'error': str(e)
|
417
|
-
})
|
418
|
-
|
419
|
-
successful = len([b for b in remediated_buckets if b['status'] == 'secured'])
|
389
|
+
remediated_buckets.append({"bucket_name": bucket_name, "status": "failed", "error": str(e)})
|
390
|
+
|
391
|
+
successful = len([b for b in remediated_buckets if b["status"] == "secured"])
|
420
392
|
print_success(f"Successfully secured {successful}/{len(bucket_names)} S3 buckets")
|
421
|
-
|
393
|
+
|
422
394
|
return {
|
423
395
|
"buckets_processed": remediated_buckets,
|
424
396
|
"successful_count": successful,
|
425
|
-
"total_count": len(bucket_names)
|
397
|
+
"total_count": len(bucket_names),
|
426
398
|
}
|
427
399
|
|
428
400
|
|
@@ -430,14 +402,13 @@ def fix_public_s3_buckets(
|
|
430
402
|
# 7. DIRECT FRAMEWORK USAGE (without decorators)
|
431
403
|
# =============================================================================
|
432
404
|
|
405
|
+
|
433
406
|
def custom_operation_with_framework(
|
434
|
-
dry_run: bool = True,
|
435
|
-
operation_name: str = "custom_operation",
|
436
|
-
resources: Optional[List[str]] = None
|
407
|
+
dry_run: bool = True, operation_name: str = "custom_operation", resources: Optional[List[str]] = None
|
437
408
|
) -> Dict[str, Any]:
|
438
409
|
"""
|
439
410
|
Example of using the dry-run framework directly without decorators.
|
440
|
-
|
411
|
+
|
441
412
|
This approach gives you full control over the dry-run behavior
|
442
413
|
and is useful for complex operations that need custom handling.
|
443
414
|
"""
|
@@ -448,19 +419,19 @@ def custom_operation_with_framework(
|
|
448
419
|
module_name="example",
|
449
420
|
operation_name=operation_name,
|
450
421
|
target_resources=resources,
|
451
|
-
estimated_impact="Moderate configuration changes"
|
422
|
+
estimated_impact="Moderate configuration changes",
|
452
423
|
)
|
453
|
-
|
424
|
+
|
454
425
|
# Display banner
|
455
426
|
framework.display_dry_run_banner(context)
|
456
|
-
|
427
|
+
|
457
428
|
# Request confirmation if needed
|
458
429
|
if not framework.confirm_operation(context):
|
459
430
|
return {"cancelled": True}
|
460
|
-
|
431
|
+
|
461
432
|
# Log operation start
|
462
433
|
framework.log_operation_start(context, {"custom_parameter": "example"})
|
463
|
-
|
434
|
+
|
464
435
|
try:
|
465
436
|
if context.enabled:
|
466
437
|
# Dry-run logic
|
@@ -471,12 +442,12 @@ def custom_operation_with_framework(
|
|
471
442
|
console.print("[green]⚡ Executing custom operation...[/green]")
|
472
443
|
# Your actual operation code here
|
473
444
|
result = {"executed": True, "resources": resources or []}
|
474
|
-
|
445
|
+
|
475
446
|
# Log success
|
476
447
|
framework.log_operation_complete(context, success=True, results=result)
|
477
|
-
|
448
|
+
|
478
449
|
return result
|
479
|
-
|
450
|
+
|
480
451
|
except Exception as e:
|
481
452
|
# Log failure
|
482
453
|
framework.log_operation_complete(context, success=False, error=str(e))
|
@@ -487,58 +458,60 @@ def custom_operation_with_framework(
|
|
487
458
|
# 8. MIGRATION HELPER FUNCTIONS
|
488
459
|
# =============================================================================
|
489
460
|
|
461
|
+
|
490
462
|
def migrate_legacy_dry_run_function(legacy_function: callable) -> callable:
|
491
463
|
"""
|
492
464
|
Helper function to migrate legacy dry-run implementations to the new framework.
|
493
|
-
|
465
|
+
|
494
466
|
This function can wrap existing functions that have their own dry-run logic
|
495
467
|
and upgrade them to use the unified framework.
|
496
468
|
"""
|
469
|
+
|
497
470
|
def wrapper(*args, **kwargs):
|
498
471
|
# Extract dry_run parameter
|
499
|
-
dry_run = kwargs.get(
|
500
|
-
|
472
|
+
dry_run = kwargs.get("dry_run", True)
|
473
|
+
|
501
474
|
# Determine operation type based on function name/behavior
|
502
475
|
func_name = legacy_function.__name__
|
503
|
-
if
|
476
|
+
if "create" in func_name or "provision" in func_name:
|
504
477
|
op_type = OperationType.RESOURCE_CREATE
|
505
|
-
elif
|
478
|
+
elif "delete" in func_name or "terminate" in func_name or "remove" in func_name:
|
506
479
|
op_type = OperationType.RESOURCE_DELETE
|
507
|
-
elif
|
480
|
+
elif "modify" in func_name or "update" in func_name or "change" in func_name:
|
508
481
|
op_type = OperationType.RESOURCE_MODIFY
|
509
|
-
elif
|
482
|
+
elif "fix" in func_name or "remediat" in func_name:
|
510
483
|
op_type = OperationType.REMEDIATION
|
511
484
|
else:
|
512
485
|
op_type = OperationType.ANALYSIS
|
513
|
-
|
486
|
+
|
514
487
|
# Create context
|
515
488
|
context = framework.create_context(
|
516
489
|
dry_run=dry_run,
|
517
490
|
operation_type=op_type,
|
518
|
-
module_name=legacy_function.__module__.split(
|
519
|
-
operation_name=func_name
|
491
|
+
module_name=legacy_function.__module__.split(".")[-2] if "." in legacy_function.__module__ else "legacy",
|
492
|
+
operation_name=func_name,
|
520
493
|
)
|
521
|
-
|
494
|
+
|
522
495
|
# Apply framework behavior
|
523
496
|
framework.display_dry_run_banner(context)
|
524
|
-
|
497
|
+
|
525
498
|
if not framework.confirm_operation(context):
|
526
499
|
return None
|
527
|
-
|
500
|
+
|
528
501
|
framework.log_operation_start(context)
|
529
|
-
|
502
|
+
|
530
503
|
try:
|
531
504
|
# Call the original function with updated context
|
532
|
-
kwargs[
|
505
|
+
kwargs["dry_run"] = context.enabled
|
533
506
|
result = legacy_function(*args, **kwargs)
|
534
|
-
|
507
|
+
|
535
508
|
framework.log_operation_complete(context, success=True, results={"migrated": True})
|
536
509
|
return result
|
537
|
-
|
510
|
+
|
538
511
|
except Exception as e:
|
539
512
|
framework.log_operation_complete(context, success=False, error=str(e))
|
540
513
|
raise
|
541
|
-
|
514
|
+
|
542
515
|
return wrapper
|
543
516
|
|
544
517
|
|
@@ -551,37 +524,29 @@ if __name__ == "__main__":
|
|
551
524
|
Example CLI usage demonstrating the dry-run framework.
|
552
525
|
"""
|
553
526
|
import click
|
554
|
-
|
527
|
+
|
555
528
|
@click.group()
|
556
529
|
def cli():
|
557
530
|
"""Example CLI with dry-run framework integration."""
|
558
531
|
pass
|
559
|
-
|
532
|
+
|
560
533
|
@cli.command()
|
561
|
-
@click.option(
|
562
|
-
@click.option(
|
563
|
-
@click.option(
|
534
|
+
@click.option("--dry-run/--no-dry-run", default=True, help="Enable dry-run mode")
|
535
|
+
@click.option("--profile", help="AWS profile name")
|
536
|
+
@click.option("--regions", multiple=True, help="AWS regions")
|
564
537
|
def discover(dry_run, profile, regions):
|
565
538
|
"""Discover EC2 instances with dry-run support."""
|
566
|
-
result = collect_ec2_instances(
|
567
|
-
profile=profile,
|
568
|
-
regions=list(regions) if regions else None,
|
569
|
-
dry_run=dry_run
|
570
|
-
)
|
539
|
+
result = collect_ec2_instances(profile=profile, regions=list(regions) if regions else None, dry_run=dry_run)
|
571
540
|
console.print(f"Discovery result: {result}")
|
572
|
-
|
541
|
+
|
573
542
|
@cli.command()
|
574
|
-
@click.option(
|
575
|
-
@click.option(
|
576
|
-
@click.option(
|
543
|
+
@click.option("--dry-run/--no-dry-run", default=True, help="Enable dry-run mode")
|
544
|
+
@click.option("--instance-type", default="t3.micro", help="Instance type")
|
545
|
+
@click.option("--profile", help="AWS profile name")
|
577
546
|
def create(dry_run, instance_type, profile):
|
578
547
|
"""Create EC2 instance with dry-run support."""
|
579
|
-
result = create_ec2_instance(
|
580
|
-
instance_type=instance_type,
|
581
|
-
profile=profile,
|
582
|
-
dry_run=dry_run
|
583
|
-
)
|
548
|
+
result = create_ec2_instance(instance_type=instance_type, profile=profile, dry_run=dry_run)
|
584
549
|
console.print(f"Creation result: {result}")
|
585
|
-
|
550
|
+
|
586
551
|
# Run CLI
|
587
|
-
cli()
|
552
|
+
cli()
|