runbooks 0.7.6__py3-none-any.whl → 0.7.9__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 +1 -1
- runbooks/base.py +5 -1
- runbooks/cfat/__init__.py +8 -4
- runbooks/cfat/assessment/collectors.py +171 -14
- runbooks/cfat/assessment/compliance.py +871 -0
- runbooks/cfat/assessment/runner.py +122 -11
- runbooks/cfat/models.py +6 -2
- runbooks/common/logger.py +14 -0
- runbooks/common/rich_utils.py +451 -0
- runbooks/enterprise/__init__.py +68 -0
- runbooks/enterprise/error_handling.py +411 -0
- runbooks/enterprise/logging.py +439 -0
- runbooks/enterprise/multi_tenant.py +583 -0
- runbooks/finops/README.md +468 -241
- runbooks/finops/__init__.py +39 -3
- runbooks/finops/cli.py +83 -18
- runbooks/finops/cross_validation.py +375 -0
- runbooks/finops/dashboard_runner.py +812 -164
- runbooks/finops/enhanced_dashboard_runner.py +525 -0
- runbooks/finops/finops_dashboard.py +1892 -0
- runbooks/finops/helpers.py +485 -51
- runbooks/finops/optimizer.py +823 -0
- runbooks/finops/tests/__init__.py +19 -0
- runbooks/finops/tests/results_test_finops_dashboard.xml +1 -0
- runbooks/finops/tests/run_comprehensive_tests.py +421 -0
- runbooks/finops/tests/run_tests.py +305 -0
- runbooks/finops/tests/test_finops_dashboard.py +705 -0
- runbooks/finops/tests/test_integration.py +477 -0
- runbooks/finops/tests/test_performance.py +380 -0
- runbooks/finops/tests/test_performance_benchmarks.py +500 -0
- runbooks/finops/tests/test_reference_images_validation.py +867 -0
- runbooks/finops/tests/test_single_account_features.py +715 -0
- runbooks/finops/tests/validate_test_suite.py +220 -0
- runbooks/finops/types.py +1 -1
- runbooks/hitl/enhanced_workflow_engine.py +725 -0
- runbooks/inventory/artifacts/scale-optimize-status.txt +12 -0
- runbooks/inventory/collectors/aws_comprehensive.py +442 -0
- runbooks/inventory/collectors/enterprise_scale.py +281 -0
- runbooks/inventory/core/collector.py +172 -13
- runbooks/inventory/discovery.md +1 -1
- runbooks/inventory/list_ec2_instances.py +18 -20
- runbooks/inventory/list_ssm_parameters.py +31 -3
- runbooks/inventory/organizations_discovery.py +1269 -0
- runbooks/inventory/rich_inventory_display.py +393 -0
- runbooks/inventory/run_on_multi_accounts.py +35 -19
- runbooks/inventory/runbooks.security.report_generator.log +0 -0
- runbooks/inventory/runbooks.security.run_script.log +0 -0
- runbooks/inventory/vpc_flow_analyzer.py +1030 -0
- runbooks/main.py +2215 -119
- runbooks/metrics/dora_metrics_engine.py +599 -0
- runbooks/operate/__init__.py +2 -2
- runbooks/operate/base.py +122 -10
- runbooks/operate/deployment_framework.py +1032 -0
- runbooks/operate/deployment_validator.py +853 -0
- runbooks/operate/dynamodb_operations.py +10 -6
- runbooks/operate/ec2_operations.py +319 -11
- runbooks/operate/executive_dashboard.py +779 -0
- runbooks/operate/mcp_integration.py +750 -0
- runbooks/operate/nat_gateway_operations.py +1120 -0
- runbooks/operate/networking_cost_heatmap.py +685 -0
- runbooks/operate/privatelink_operations.py +940 -0
- runbooks/operate/s3_operations.py +10 -6
- runbooks/operate/vpc_endpoints.py +644 -0
- runbooks/operate/vpc_operations.py +1038 -0
- runbooks/remediation/__init__.py +2 -2
- runbooks/remediation/acm_remediation.py +1 -1
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/cloudtrail_remediation.py +1 -1
- runbooks/remediation/cognito_remediation.py +1 -1
- runbooks/remediation/dynamodb_remediation.py +1 -1
- runbooks/remediation/ec2_remediation.py +1 -1
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -1
- runbooks/remediation/kms_enable_key_rotation.py +1 -1
- runbooks/remediation/kms_remediation.py +1 -1
- runbooks/remediation/lambda_remediation.py +1 -1
- runbooks/remediation/multi_account.py +1 -1
- runbooks/remediation/rds_remediation.py +1 -1
- runbooks/remediation/s3_block_public_access.py +1 -1
- runbooks/remediation/s3_enable_access_logging.py +1 -1
- runbooks/remediation/s3_encryption.py +1 -1
- runbooks/remediation/s3_remediation.py +1 -1
- runbooks/remediation/vpc_remediation.py +475 -0
- runbooks/security/__init__.py +3 -1
- runbooks/security/compliance_automation.py +632 -0
- runbooks/security/report_generator.py +10 -0
- runbooks/security/run_script.py +31 -5
- runbooks/security/security_baseline_tester.py +169 -30
- runbooks/security/security_export.py +477 -0
- runbooks/validation/__init__.py +10 -0
- runbooks/validation/benchmark.py +484 -0
- runbooks/validation/cli.py +356 -0
- runbooks/validation/mcp_validator.py +768 -0
- runbooks/vpc/__init__.py +38 -0
- runbooks/vpc/config.py +212 -0
- runbooks/vpc/cost_engine.py +347 -0
- runbooks/vpc/heatmap_engine.py +605 -0
- runbooks/vpc/manager_interface.py +634 -0
- runbooks/vpc/networking_wrapper.py +1260 -0
- runbooks/vpc/rich_formatters.py +679 -0
- runbooks/vpc/tests/__init__.py +5 -0
- runbooks/vpc/tests/conftest.py +356 -0
- runbooks/vpc/tests/test_cli_integration.py +530 -0
- runbooks/vpc/tests/test_config.py +458 -0
- runbooks/vpc/tests/test_cost_engine.py +479 -0
- runbooks/vpc/tests/test_networking_wrapper.py +512 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/METADATA +40 -12
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/RECORD +111 -50
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/WHEEL +0 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/entry_points.txt +0 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/licenses/LICENSE +0 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,458 @@
|
|
1
|
+
"""
|
2
|
+
Tests for VPC Configuration Management
|
3
|
+
|
4
|
+
Tests the configuration system for VPC networking operations,
|
5
|
+
including environment variable handling and validation.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import os
|
9
|
+
import tempfile
|
10
|
+
from unittest.mock import Mock, patch
|
11
|
+
|
12
|
+
import pytest
|
13
|
+
|
14
|
+
from runbooks.vpc.config import (
|
15
|
+
AWSCostModel,
|
16
|
+
OptimizationThresholds,
|
17
|
+
RegionalConfiguration,
|
18
|
+
VPCNetworkingConfig,
|
19
|
+
load_config,
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
@pytest.mark.unit
|
24
|
+
class TestAWSCostModel:
|
25
|
+
"""Test AWS Cost Model configuration."""
|
26
|
+
|
27
|
+
def test_default_cost_model(self):
|
28
|
+
"""Test default AWS cost model values."""
|
29
|
+
cost_model = AWSCostModel()
|
30
|
+
|
31
|
+
# NAT Gateway pricing defaults
|
32
|
+
assert cost_model.nat_gateway_hourly == 0.045
|
33
|
+
assert cost_model.nat_gateway_monthly == 45.0
|
34
|
+
assert cost_model.nat_gateway_data_processing == 0.045
|
35
|
+
|
36
|
+
# Transit Gateway pricing defaults
|
37
|
+
assert cost_model.transit_gateway_hourly == 0.05
|
38
|
+
assert cost_model.transit_gateway_monthly == 36.50
|
39
|
+
assert cost_model.transit_gateway_attachment == 0.05
|
40
|
+
assert cost_model.transit_gateway_data_processing == 0.02
|
41
|
+
|
42
|
+
# VPC Endpoint pricing defaults
|
43
|
+
assert cost_model.vpc_endpoint_interface_hourly == 0.01
|
44
|
+
assert cost_model.vpc_endpoint_interface_monthly == 10.0
|
45
|
+
assert cost_model.vpc_endpoint_gateway == 0.0
|
46
|
+
assert cost_model.vpc_endpoint_data_processing == 0.01
|
47
|
+
|
48
|
+
# Elastic IP pricing defaults
|
49
|
+
assert cost_model.elastic_ip_idle_hourly == 0.005
|
50
|
+
assert cost_model.elastic_ip_idle_monthly == 3.60
|
51
|
+
assert cost_model.elastic_ip_attached == 0.0
|
52
|
+
assert cost_model.elastic_ip_remap == 0.10
|
53
|
+
|
54
|
+
def test_cost_model_with_environment_variables(self):
|
55
|
+
"""Test cost model with custom environment variables."""
|
56
|
+
env_vars = {
|
57
|
+
"AWS_NAT_GATEWAY_HOURLY": "0.050",
|
58
|
+
"AWS_NAT_GATEWAY_MONTHLY": "50.0",
|
59
|
+
"AWS_VPC_ENDPOINT_INTERFACE_MONTHLY": "12.0",
|
60
|
+
"AWS_ELASTIC_IP_IDLE_MONTHLY": "4.0",
|
61
|
+
}
|
62
|
+
|
63
|
+
with patch.dict(os.environ, env_vars):
|
64
|
+
cost_model = AWSCostModel()
|
65
|
+
|
66
|
+
assert cost_model.nat_gateway_hourly == 0.050
|
67
|
+
assert cost_model.nat_gateway_monthly == 50.0
|
68
|
+
assert cost_model.vpc_endpoint_interface_monthly == 12.0
|
69
|
+
assert cost_model.elastic_ip_idle_monthly == 4.0
|
70
|
+
|
71
|
+
def test_cost_model_data_transfer_pricing(self):
|
72
|
+
"""Test data transfer pricing configuration."""
|
73
|
+
cost_model = AWSCostModel()
|
74
|
+
|
75
|
+
assert cost_model.data_transfer_inter_az == 0.01
|
76
|
+
assert cost_model.data_transfer_inter_region == 0.02
|
77
|
+
assert cost_model.data_transfer_internet_out == 0.09
|
78
|
+
assert cost_model.data_transfer_s3_same_region == 0.0 # Always free
|
79
|
+
|
80
|
+
|
81
|
+
@pytest.mark.unit
|
82
|
+
class TestOptimizationThresholds:
|
83
|
+
"""Test optimization thresholds configuration."""
|
84
|
+
|
85
|
+
def test_default_optimization_thresholds(self):
|
86
|
+
"""Test default optimization threshold values."""
|
87
|
+
thresholds = OptimizationThresholds()
|
88
|
+
|
89
|
+
# Usage thresholds
|
90
|
+
assert thresholds.idle_connection_threshold == 10
|
91
|
+
assert thresholds.low_usage_gb_threshold == 100.0
|
92
|
+
assert thresholds.low_connection_threshold == 100
|
93
|
+
|
94
|
+
# Cost thresholds
|
95
|
+
assert thresholds.high_cost_threshold == 100.0
|
96
|
+
assert thresholds.critical_cost_threshold == 500.0
|
97
|
+
|
98
|
+
# Optimization targets
|
99
|
+
assert thresholds.target_reduction_percent == 30.0
|
100
|
+
|
101
|
+
# Enterprise thresholds
|
102
|
+
assert thresholds.cost_approval_threshold == 1000.0
|
103
|
+
assert thresholds.performance_baseline_threshold == 2.0
|
104
|
+
|
105
|
+
def test_optimization_thresholds_with_environment(self):
|
106
|
+
"""Test optimization thresholds with environment variables."""
|
107
|
+
env_vars = {
|
108
|
+
"IDLE_CONNECTION_THRESHOLD": "20",
|
109
|
+
"LOW_USAGE_GB_THRESHOLD": "150.0",
|
110
|
+
"TARGET_REDUCTION_PERCENT": "40.0",
|
111
|
+
"COST_APPROVAL_THRESHOLD": "2000.0",
|
112
|
+
"PERFORMANCE_BASELINE_THRESHOLD": "1.5",
|
113
|
+
}
|
114
|
+
|
115
|
+
with patch.dict(os.environ, env_vars):
|
116
|
+
thresholds = OptimizationThresholds()
|
117
|
+
|
118
|
+
assert thresholds.idle_connection_threshold == 20
|
119
|
+
assert thresholds.low_usage_gb_threshold == 150.0
|
120
|
+
assert thresholds.target_reduction_percent == 40.0
|
121
|
+
assert thresholds.cost_approval_threshold == 2000.0
|
122
|
+
assert thresholds.performance_baseline_threshold == 1.5
|
123
|
+
|
124
|
+
def test_threshold_validation_logic(self):
|
125
|
+
"""Test threshold validation and logic."""
|
126
|
+
thresholds = OptimizationThresholds()
|
127
|
+
|
128
|
+
# Test threshold relationships
|
129
|
+
assert thresholds.idle_connection_threshold < thresholds.low_connection_threshold
|
130
|
+
assert thresholds.high_cost_threshold < thresholds.critical_cost_threshold
|
131
|
+
assert 0 < thresholds.target_reduction_percent < 100
|
132
|
+
|
133
|
+
|
134
|
+
@pytest.mark.unit
|
135
|
+
class TestRegionalConfiguration:
|
136
|
+
"""Test regional configuration settings."""
|
137
|
+
|
138
|
+
def test_default_regional_configuration(self):
|
139
|
+
"""Test default regional configuration."""
|
140
|
+
regional = RegionalConfiguration()
|
141
|
+
|
142
|
+
# Default regions
|
143
|
+
expected_regions = [
|
144
|
+
"us-east-1",
|
145
|
+
"us-west-2",
|
146
|
+
"us-west-1",
|
147
|
+
"eu-west-1",
|
148
|
+
"eu-central-1",
|
149
|
+
"eu-west-2",
|
150
|
+
"ap-southeast-1",
|
151
|
+
"ap-southeast-2",
|
152
|
+
"ap-northeast-1",
|
153
|
+
]
|
154
|
+
assert regional.default_regions == expected_regions
|
155
|
+
|
156
|
+
# Regional multipliers
|
157
|
+
assert "us-east-1" in regional.regional_multipliers
|
158
|
+
assert "eu-west-1" in regional.regional_multipliers
|
159
|
+
assert "ap-southeast-1" in regional.regional_multipliers
|
160
|
+
|
161
|
+
# Validate multiplier values are positive
|
162
|
+
for region, multiplier in regional.regional_multipliers.items():
|
163
|
+
assert multiplier > 0, f"Invalid multiplier for {region}: {multiplier}"
|
164
|
+
|
165
|
+
def test_regional_multipliers_with_environment(self):
|
166
|
+
"""Test regional multipliers with environment variables."""
|
167
|
+
env_vars = {
|
168
|
+
"COST_MULTIPLIER_US_EAST_1": "2.0",
|
169
|
+
"COST_MULTIPLIER_EU_WEST_1": "1.5",
|
170
|
+
"COST_MULTIPLIER_AP_SOUTHEAST_1": "1.8",
|
171
|
+
}
|
172
|
+
|
173
|
+
with patch.dict(os.environ, env_vars):
|
174
|
+
regional = RegionalConfiguration()
|
175
|
+
|
176
|
+
assert regional.regional_multipliers["us-east-1"] == 2.0
|
177
|
+
assert regional.regional_multipliers["eu-west-1"] == 1.5
|
178
|
+
assert regional.regional_multipliers["ap-southeast-1"] == 1.8
|
179
|
+
|
180
|
+
def test_regional_configuration_coverage(self):
|
181
|
+
"""Test that regional configuration covers major AWS regions."""
|
182
|
+
regional = RegionalConfiguration()
|
183
|
+
|
184
|
+
# Check major regions are covered
|
185
|
+
major_regions = ["us-east-1", "us-west-2", "eu-west-1", "ap-southeast-1"]
|
186
|
+
for region in major_regions:
|
187
|
+
assert region in regional.default_regions
|
188
|
+
assert region in regional.regional_multipliers
|
189
|
+
|
190
|
+
|
191
|
+
@pytest.mark.unit
|
192
|
+
class TestVPCNetworkingConfig:
|
193
|
+
"""Test main VPC networking configuration."""
|
194
|
+
|
195
|
+
def test_default_vpc_networking_config(self):
|
196
|
+
"""Test default VPC networking configuration."""
|
197
|
+
config = VPCNetworkingConfig()
|
198
|
+
|
199
|
+
# AWS configuration
|
200
|
+
assert config.default_region == "us-east-1"
|
201
|
+
assert config.billing_profile is None
|
202
|
+
assert config.centralized_ops_profile is None
|
203
|
+
assert config.single_account_profile is None
|
204
|
+
assert config.management_profile is None
|
205
|
+
|
206
|
+
# Analysis configuration
|
207
|
+
assert config.default_analysis_days == 30
|
208
|
+
assert config.forecast_days == 90
|
209
|
+
|
210
|
+
# Output configuration
|
211
|
+
assert config.default_output_format == "rich"
|
212
|
+
assert str(config.default_output_dir) in ["./exports", "exports"]
|
213
|
+
|
214
|
+
# Enterprise configuration
|
215
|
+
assert config.enable_cost_approval_workflow is True
|
216
|
+
assert config.enable_mcp_validation is False
|
217
|
+
|
218
|
+
# Component configurations
|
219
|
+
assert isinstance(config.cost_model, AWSCostModel)
|
220
|
+
assert isinstance(config.thresholds, OptimizationThresholds)
|
221
|
+
assert isinstance(config.regional, RegionalConfiguration)
|
222
|
+
|
223
|
+
def test_vpc_config_with_environment_variables(self):
|
224
|
+
"""Test VPC configuration with environment variables."""
|
225
|
+
env_vars = {
|
226
|
+
"AWS_DEFAULT_REGION": "us-west-2",
|
227
|
+
"BILLING_PROFILE": "test-billing-profile",
|
228
|
+
"CENTRALIZED_OPS_PROFILE": "test-ops-profile",
|
229
|
+
"SINGLE_ACCOUNT_PROFILE": "test-single-profile",
|
230
|
+
"MANAGEMENT_PROFILE": "test-mgmt-profile",
|
231
|
+
"DEFAULT_ANALYSIS_DAYS": "45",
|
232
|
+
"FORECAST_DAYS": "120",
|
233
|
+
"OUTPUT_FORMAT": "json",
|
234
|
+
"OUTPUT_DIR": "/tmp/vpc-exports",
|
235
|
+
"ENABLE_COST_APPROVAL_WORKFLOW": "false",
|
236
|
+
"ENABLE_MCP_VALIDATION": "true",
|
237
|
+
}
|
238
|
+
|
239
|
+
with patch.dict(os.environ, env_vars):
|
240
|
+
config = VPCNetworkingConfig()
|
241
|
+
|
242
|
+
assert config.default_region == "us-west-2"
|
243
|
+
assert config.billing_profile == "test-billing-profile"
|
244
|
+
assert config.centralized_ops_profile == "test-ops-profile"
|
245
|
+
assert config.single_account_profile == "test-single-profile"
|
246
|
+
assert config.management_profile == "test-mgmt-profile"
|
247
|
+
assert config.default_analysis_days == 45
|
248
|
+
assert config.forecast_days == 120
|
249
|
+
assert config.default_output_format == "json"
|
250
|
+
assert str(config.default_output_dir) == "/tmp/vpc-exports"
|
251
|
+
assert config.enable_cost_approval_workflow is False
|
252
|
+
assert config.enable_mcp_validation is True
|
253
|
+
|
254
|
+
def test_cost_approval_required_method(self):
|
255
|
+
"""Test cost approval required logic."""
|
256
|
+
config = VPCNetworkingConfig()
|
257
|
+
|
258
|
+
# Test below threshold
|
259
|
+
assert not config.get_cost_approval_required(500.0)
|
260
|
+
|
261
|
+
# Test above threshold
|
262
|
+
assert config.get_cost_approval_required(1500.0)
|
263
|
+
|
264
|
+
# Test with disabled approval workflow
|
265
|
+
config.enable_cost_approval_workflow = False
|
266
|
+
assert not config.get_cost_approval_required(1500.0)
|
267
|
+
|
268
|
+
def test_performance_acceptable_method(self):
|
269
|
+
"""Test performance acceptable logic."""
|
270
|
+
config = VPCNetworkingConfig()
|
271
|
+
|
272
|
+
# Test acceptable performance
|
273
|
+
assert config.get_performance_acceptable(1.5)
|
274
|
+
|
275
|
+
# Test unacceptable performance
|
276
|
+
assert not config.get_performance_acceptable(3.0)
|
277
|
+
|
278
|
+
# Test exact threshold
|
279
|
+
assert config.get_performance_acceptable(2.0)
|
280
|
+
|
281
|
+
def test_regional_multiplier_method(self):
|
282
|
+
"""Test regional multiplier retrieval."""
|
283
|
+
config = VPCNetworkingConfig()
|
284
|
+
|
285
|
+
# Test known region
|
286
|
+
multiplier = config.get_regional_multiplier("us-east-1")
|
287
|
+
assert multiplier > 0
|
288
|
+
|
289
|
+
# Test unknown region (should return default)
|
290
|
+
multiplier = config.get_regional_multiplier("unknown-region")
|
291
|
+
assert multiplier == 1.0
|
292
|
+
|
293
|
+
def test_config_component_relationships(self):
|
294
|
+
"""Test relationships between configuration components."""
|
295
|
+
config = VPCNetworkingConfig()
|
296
|
+
|
297
|
+
# Validate cost model thresholds align with optimization thresholds
|
298
|
+
assert config.cost_model.nat_gateway_monthly == 45.0
|
299
|
+
assert config.thresholds.cost_approval_threshold == 1000.0
|
300
|
+
|
301
|
+
# Validate that approval threshold is reasonable compared to costs
|
302
|
+
monthly_nat_cost = config.cost_model.nat_gateway_monthly
|
303
|
+
approval_threshold = config.thresholds.cost_approval_threshold
|
304
|
+
assert approval_threshold > monthly_nat_cost * 10 # Should require many resources
|
305
|
+
|
306
|
+
|
307
|
+
@pytest.mark.unit
|
308
|
+
class TestLoadConfig:
|
309
|
+
"""Test configuration loading function."""
|
310
|
+
|
311
|
+
def test_load_default_config(self):
|
312
|
+
"""Test loading default configuration."""
|
313
|
+
config = load_config()
|
314
|
+
|
315
|
+
assert isinstance(config, VPCNetworkingConfig)
|
316
|
+
assert isinstance(config.cost_model, AWSCostModel)
|
317
|
+
assert isinstance(config.thresholds, OptimizationThresholds)
|
318
|
+
assert isinstance(config.regional, RegionalConfiguration)
|
319
|
+
|
320
|
+
def test_load_config_validation_success(self):
|
321
|
+
"""Test configuration validation success."""
|
322
|
+
env_vars = {"BILLING_PROFILE": "test-billing-profile", "ENABLE_COST_APPROVAL_WORKFLOW": "true"}
|
323
|
+
|
324
|
+
with patch.dict(os.environ, env_vars):
|
325
|
+
config = load_config()
|
326
|
+
|
327
|
+
assert config.billing_profile == "test-billing-profile"
|
328
|
+
assert config.enable_cost_approval_workflow is True
|
329
|
+
|
330
|
+
def test_load_config_validation_failure(self):
|
331
|
+
"""Test configuration validation failure."""
|
332
|
+
env_vars = {
|
333
|
+
"ENABLE_COST_APPROVAL_WORKFLOW": "true",
|
334
|
+
"BILLING_PROFILE": "", # Empty billing profile
|
335
|
+
}
|
336
|
+
|
337
|
+
with patch.dict(os.environ, env_vars, clear=True):
|
338
|
+
with pytest.raises(ValueError, match="BILLING_PROFILE required"):
|
339
|
+
load_config()
|
340
|
+
|
341
|
+
def test_load_config_with_file_parameter(self):
|
342
|
+
"""Test loading configuration with config file parameter."""
|
343
|
+
# TODO: Implement when config file support is added
|
344
|
+
config = load_config(config_file=None)
|
345
|
+
|
346
|
+
# Should work with None (uses environment variables)
|
347
|
+
assert isinstance(config, VPCNetworkingConfig)
|
348
|
+
|
349
|
+
@pytest.mark.integration
|
350
|
+
def test_configuration_environment_isolation(self):
|
351
|
+
"""Test that configuration properly isolates environment variables."""
|
352
|
+
# Set initial environment
|
353
|
+
initial_env = {"AWS_DEFAULT_REGION": "us-east-1", "BILLING_PROFILE": "initial-profile"}
|
354
|
+
|
355
|
+
with patch.dict(os.environ, initial_env, clear=True):
|
356
|
+
config1 = load_config()
|
357
|
+
assert config1.default_region == "us-east-1"
|
358
|
+
assert config1.billing_profile == "initial-profile"
|
359
|
+
|
360
|
+
# Change environment
|
361
|
+
changed_env = {"AWS_DEFAULT_REGION": "us-west-2", "BILLING_PROFILE": "changed-profile"}
|
362
|
+
|
363
|
+
with patch.dict(os.environ, changed_env, clear=True):
|
364
|
+
config2 = load_config()
|
365
|
+
assert config2.default_region == "us-west-2"
|
366
|
+
assert config2.billing_profile == "changed-profile"
|
367
|
+
|
368
|
+
# Confirm original config unchanged
|
369
|
+
assert config1.default_region == "us-east-1"
|
370
|
+
assert config1.billing_profile == "initial-profile"
|
371
|
+
|
372
|
+
|
373
|
+
@pytest.mark.performance
|
374
|
+
class TestConfigurationPerformance:
|
375
|
+
"""Test configuration loading performance."""
|
376
|
+
|
377
|
+
def test_config_loading_performance(self):
|
378
|
+
"""Test configuration loading performance benchmark."""
|
379
|
+
import time
|
380
|
+
|
381
|
+
start_time = time.time()
|
382
|
+
|
383
|
+
# Load configuration multiple times
|
384
|
+
for _ in range(10):
|
385
|
+
config = load_config()
|
386
|
+
|
387
|
+
execution_time = time.time() - start_time
|
388
|
+
|
389
|
+
# Configuration loading should be very fast
|
390
|
+
assert execution_time < 1.0, f"Configuration loading too slow: {execution_time:.2f}s"
|
391
|
+
|
392
|
+
def test_config_memory_usage(self):
|
393
|
+
"""Test configuration memory efficiency."""
|
394
|
+
import sys
|
395
|
+
|
396
|
+
# Get initial memory usage
|
397
|
+
initial_size = sys.getsizeof({})
|
398
|
+
|
399
|
+
config = load_config()
|
400
|
+
|
401
|
+
# Configuration should not use excessive memory
|
402
|
+
config_size = sys.getsizeof(config.__dict__)
|
403
|
+
|
404
|
+
# Should be reasonable for configuration data
|
405
|
+
assert config_size < 10000, f"Configuration using too much memory: {config_size} bytes"
|
406
|
+
|
407
|
+
|
408
|
+
@pytest.mark.security
|
409
|
+
class TestConfigurationSecurity:
|
410
|
+
"""Test configuration security aspects."""
|
411
|
+
|
412
|
+
def test_no_credentials_in_config(self):
|
413
|
+
"""Test that configuration doesn't expose credentials."""
|
414
|
+
config = load_config()
|
415
|
+
|
416
|
+
# Convert config to string representation
|
417
|
+
config_str = str(config.__dict__)
|
418
|
+
|
419
|
+
# Check for common credential patterns
|
420
|
+
sensitive_patterns = ["AKIA", "SECRET", "TOKEN", "PASSWORD", "KEY"]
|
421
|
+
for pattern in sensitive_patterns:
|
422
|
+
assert pattern not in config_str.upper(), f"Potentially sensitive pattern '{pattern}' found in config"
|
423
|
+
|
424
|
+
def test_profile_name_validation(self):
|
425
|
+
"""Test profile name validation and sanitization."""
|
426
|
+
# Test with potentially dangerous profile names
|
427
|
+
dangerous_profiles = ["profile; rm -rf /", "profile && malicious_command", "profile | grep secrets"]
|
428
|
+
|
429
|
+
for dangerous_profile in dangerous_profiles:
|
430
|
+
env_vars = {"BILLING_PROFILE": dangerous_profile}
|
431
|
+
|
432
|
+
with patch.dict(os.environ, env_vars):
|
433
|
+
config = load_config()
|
434
|
+
|
435
|
+
# Profile name should be stored as-is (validation happens at usage)
|
436
|
+
assert config.billing_profile == dangerous_profile
|
437
|
+
|
438
|
+
def test_environment_variable_precedence(self):
|
439
|
+
"""Test environment variable precedence and override behavior."""
|
440
|
+
# Set base environment
|
441
|
+
base_env = {"AWS_DEFAULT_REGION": "us-east-1", "BILLING_PROFILE": "base-profile"}
|
442
|
+
|
443
|
+
with patch.dict(os.environ, base_env):
|
444
|
+
config = load_config()
|
445
|
+
|
446
|
+
# Verify base values
|
447
|
+
assert config.default_region == "us-east-1"
|
448
|
+
assert config.billing_profile == "base-profile"
|
449
|
+
|
450
|
+
# Override with new values
|
451
|
+
override_env = {"AWS_DEFAULT_REGION": "eu-west-1", "BILLING_PROFILE": "override-profile"}
|
452
|
+
|
453
|
+
with patch.dict(os.environ, override_env):
|
454
|
+
config_override = load_config()
|
455
|
+
|
456
|
+
# Verify override values
|
457
|
+
assert config_override.default_region == "eu-west-1"
|
458
|
+
assert config_override.billing_profile == "override-profile"
|