complio 0.1.1__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 (79) hide show
  1. CHANGELOG.md +208 -0
  2. README.md +343 -0
  3. complio/__init__.py +48 -0
  4. complio/cli/__init__.py +0 -0
  5. complio/cli/banner.py +87 -0
  6. complio/cli/commands/__init__.py +0 -0
  7. complio/cli/commands/history.py +439 -0
  8. complio/cli/commands/scan.py +700 -0
  9. complio/cli/main.py +115 -0
  10. complio/cli/output.py +338 -0
  11. complio/config/__init__.py +17 -0
  12. complio/config/settings.py +333 -0
  13. complio/connectors/__init__.py +9 -0
  14. complio/connectors/aws/__init__.py +0 -0
  15. complio/connectors/aws/client.py +342 -0
  16. complio/connectors/base.py +135 -0
  17. complio/core/__init__.py +10 -0
  18. complio/core/registry.py +228 -0
  19. complio/core/runner.py +351 -0
  20. complio/py.typed +0 -0
  21. complio/reporters/__init__.py +7 -0
  22. complio/reporters/generator.py +417 -0
  23. complio/tests_library/__init__.py +0 -0
  24. complio/tests_library/base.py +492 -0
  25. complio/tests_library/identity/__init__.py +0 -0
  26. complio/tests_library/identity/access_key_rotation.py +302 -0
  27. complio/tests_library/identity/mfa_enforcement.py +327 -0
  28. complio/tests_library/identity/root_account_protection.py +470 -0
  29. complio/tests_library/infrastructure/__init__.py +0 -0
  30. complio/tests_library/infrastructure/cloudtrail_encryption.py +286 -0
  31. complio/tests_library/infrastructure/cloudtrail_log_validation.py +274 -0
  32. complio/tests_library/infrastructure/cloudtrail_logging.py +400 -0
  33. complio/tests_library/infrastructure/ebs_encryption.py +244 -0
  34. complio/tests_library/infrastructure/ec2_security_groups.py +321 -0
  35. complio/tests_library/infrastructure/iam_password_policy.py +460 -0
  36. complio/tests_library/infrastructure/nacl_security.py +356 -0
  37. complio/tests_library/infrastructure/rds_encryption.py +252 -0
  38. complio/tests_library/infrastructure/s3_encryption.py +301 -0
  39. complio/tests_library/infrastructure/s3_public_access.py +369 -0
  40. complio/tests_library/infrastructure/secrets_manager_encryption.py +248 -0
  41. complio/tests_library/infrastructure/vpc_flow_logs.py +287 -0
  42. complio/tests_library/logging/__init__.py +0 -0
  43. complio/tests_library/logging/cloudwatch_alarms.py +354 -0
  44. complio/tests_library/logging/cloudwatch_logs_encryption.py +281 -0
  45. complio/tests_library/logging/cloudwatch_retention.py +252 -0
  46. complio/tests_library/logging/config_enabled.py +393 -0
  47. complio/tests_library/logging/eventbridge_rules.py +460 -0
  48. complio/tests_library/logging/guardduty_enabled.py +436 -0
  49. complio/tests_library/logging/security_hub_enabled.py +416 -0
  50. complio/tests_library/logging/sns_encryption.py +273 -0
  51. complio/tests_library/network/__init__.py +0 -0
  52. complio/tests_library/network/alb_nlb_security.py +421 -0
  53. complio/tests_library/network/api_gateway_security.py +452 -0
  54. complio/tests_library/network/cloudfront_https.py +332 -0
  55. complio/tests_library/network/direct_connect_security.py +343 -0
  56. complio/tests_library/network/nacl_configuration.py +367 -0
  57. complio/tests_library/network/network_firewall.py +355 -0
  58. complio/tests_library/network/transit_gateway_security.py +318 -0
  59. complio/tests_library/network/vpc_endpoints_security.py +339 -0
  60. complio/tests_library/network/vpn_security.py +333 -0
  61. complio/tests_library/network/waf_configuration.py +428 -0
  62. complio/tests_library/security/__init__.py +0 -0
  63. complio/tests_library/security/kms_key_rotation.py +314 -0
  64. complio/tests_library/storage/__init__.py +0 -0
  65. complio/tests_library/storage/backup_encryption.py +288 -0
  66. complio/tests_library/storage/dynamodb_encryption.py +280 -0
  67. complio/tests_library/storage/efs_encryption.py +257 -0
  68. complio/tests_library/storage/elasticache_encryption.py +370 -0
  69. complio/tests_library/storage/redshift_encryption.py +252 -0
  70. complio/tests_library/storage/s3_versioning.py +264 -0
  71. complio/utils/__init__.py +26 -0
  72. complio/utils/errors.py +179 -0
  73. complio/utils/exceptions.py +151 -0
  74. complio/utils/history.py +243 -0
  75. complio/utils/logger.py +391 -0
  76. complio-0.1.1.dist-info/METADATA +385 -0
  77. complio-0.1.1.dist-info/RECORD +79 -0
  78. complio-0.1.1.dist-info/WHEEL +4 -0
  79. complio-0.1.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,264 @@
1
+ """
2
+ S3 bucket versioning compliance test.
3
+
4
+ Checks that all S3 buckets have versioning enabled for data recovery.
5
+
6
+ ISO 27001 Control: A.8.13 - Information backup
7
+ Requirement: S3 buckets must have versioning enabled
8
+
9
+ Example:
10
+ >>> from complio.connectors.aws.client import AWSConnector
11
+ >>> from complio.tests_library.storage.s3_versioning import S3VersioningTest
12
+ >>>
13
+ >>> connector = AWSConnector("production", "us-east-1")
14
+ >>> connector.connect()
15
+ >>>
16
+ >>> test = S3VersioningTest(connector)
17
+ >>> result = test.run()
18
+ >>> print(f"Passed: {result.passed}, Score: {result.score}")
19
+ """
20
+
21
+ from typing import Any, Dict
22
+
23
+ from botocore.exceptions import ClientError
24
+
25
+ from complio.connectors.aws.client import AWSConnector
26
+ from complio.tests_library.base import (
27
+ ComplianceTest,
28
+ Severity,
29
+ TestResult,
30
+ TestStatus,
31
+ )
32
+
33
+
34
+ class S3VersioningTest(ComplianceTest):
35
+ """Test for S3 bucket versioning compliance.
36
+
37
+ Verifies that all S3 buckets have versioning enabled to protect
38
+ against accidental deletion and provide data recovery capabilities.
39
+
40
+ Compliance Requirements:
41
+ - All S3 buckets must have versioning enabled (Status='Enabled')
42
+ - MFA Delete is recommended for additional protection (bonus check)
43
+ - Versioning protects against accidental deletion and modification
44
+
45
+ Scoring:
46
+ - 100% if all buckets have versioning enabled
47
+ - Proportional score based on compliant/total ratio
48
+ - 0% if no buckets have versioning enabled
49
+
50
+ Example:
51
+ >>> test = S3VersioningTest(connector)
52
+ >>> result = test.execute()
53
+ >>> for finding in result.findings:
54
+ ... print(f"{finding.resource_id}: {finding.title}")
55
+ """
56
+
57
+ def __init__(self, connector: AWSConnector) -> None:
58
+ """Initialize S3 versioning test.
59
+
60
+ Args:
61
+ connector: AWS connector instance
62
+ """
63
+ super().__init__(
64
+ test_id="s3_versioning",
65
+ test_name="S3 Bucket Versioning Check",
66
+ description="Verify all S3 buckets have versioning enabled for data recovery",
67
+ control_id="A.8.13",
68
+ connector=connector,
69
+ scope="global",
70
+ )
71
+
72
+ def execute(self) -> TestResult:
73
+ """Execute S3 bucket versioning compliance test.
74
+
75
+ Returns:
76
+ TestResult with findings for buckets without versioning
77
+
78
+ Example:
79
+ >>> test = S3VersioningTest(connector)
80
+ >>> result = test.execute()
81
+ >>> print(result.score)
82
+ 85.0
83
+ """
84
+ result = TestResult(
85
+ test_id=self.test_id,
86
+ test_name=self.test_name,
87
+ status=TestStatus.PASSED,
88
+ passed=True,
89
+ score=100.0,
90
+ )
91
+
92
+ try:
93
+ # Get S3 client
94
+ s3_client = self.connector.get_client("s3")
95
+
96
+ # List all buckets
97
+ self.logger.info("listing_s3_buckets")
98
+ buckets_response = s3_client.list_buckets()
99
+ buckets = buckets_response.get("Buckets", [])
100
+
101
+ if not buckets:
102
+ self.logger.info("no_s3_buckets_found")
103
+ result.metadata["message"] = "No S3 buckets found in account"
104
+ return result
105
+
106
+ self.logger.info("s3_buckets_found", count=len(buckets))
107
+
108
+ # Check versioning for each bucket
109
+ versioning_enabled_count = 0
110
+
111
+ for bucket in buckets:
112
+ bucket_name = bucket["Name"]
113
+ result.resources_scanned += 1
114
+
115
+ try:
116
+ # Get bucket versioning configuration
117
+ versioning_response = s3_client.get_bucket_versioning(Bucket=bucket_name)
118
+
119
+ # Check versioning status
120
+ versioning_status = versioning_response.get("Status", "Disabled")
121
+ mfa_delete = versioning_response.get("MFADelete", "Disabled")
122
+
123
+ versioning_enabled = versioning_status == "Enabled"
124
+
125
+ # Create evidence
126
+ evidence = self.create_evidence(
127
+ resource_id=bucket_name,
128
+ resource_type="s3_bucket",
129
+ data={
130
+ "bucket_name": bucket_name,
131
+ "versioning_status": versioning_status,
132
+ "mfa_delete": mfa_delete,
133
+ "creation_date": bucket.get("CreationDate").isoformat() if bucket.get("CreationDate") else None,
134
+ }
135
+ )
136
+ result.add_evidence(evidence)
137
+
138
+ if versioning_enabled:
139
+ versioning_enabled_count += 1
140
+ self.logger.debug(
141
+ "bucket_versioning_enabled",
142
+ bucket=bucket_name,
143
+ mfa_delete=mfa_delete
144
+ )
145
+ else:
146
+ # Create finding for bucket without versioning
147
+ finding = self.create_finding(
148
+ resource_id=bucket_name,
149
+ resource_type="s3_bucket",
150
+ severity=Severity.MEDIUM,
151
+ title="S3 bucket versioning not enabled",
152
+ description=f"S3 bucket '{bucket_name}' does not have versioning enabled "
153
+ f"(current status: {versioning_status}). Without versioning, objects "
154
+ "can be permanently deleted or overwritten accidentally. Versioning "
155
+ "protects against unintended user actions, application failures, and "
156
+ "provides the ability to recover previous versions. "
157
+ "ISO 27001 A.8.13 requires proper backup and recovery capabilities.",
158
+ remediation=(
159
+ f"Enable versioning for S3 bucket '{bucket_name}':\n\n"
160
+ "Using AWS CLI:\n"
161
+ f"aws s3api put-bucket-versioning --bucket {bucket_name} \\\n"
162
+ " --versioning-configuration Status=Enabled\n\n"
163
+ "Or use AWS Console:\n"
164
+ "1. Go to AWS S3 console\n"
165
+ f"2. Select bucket '{bucket_name}'\n"
166
+ "3. Go to 'Properties' tab\n"
167
+ "4. Under 'Bucket Versioning', click 'Edit'\n"
168
+ "5. Select 'Enable'\n"
169
+ "6. Click 'Save changes'\n\n"
170
+ "Optional: Enable MFA Delete for additional protection:\n"
171
+ f"aws s3api put-bucket-versioning --bucket {bucket_name} \\\n"
172
+ " --versioning-configuration Status=Enabled,MFADelete=Enabled \\\n"
173
+ " --mfa \"arn:aws:iam::ACCOUNT-ID:mfa/root-account-mfa-device XXXXXX\"\n\n"
174
+ "Note: MFA Delete requires root account credentials.\n"
175
+ "Consider lifecycle policies to manage versioned objects and costs."
176
+ ),
177
+ evidence=evidence
178
+ )
179
+ result.add_finding(finding)
180
+
181
+ self.logger.warning(
182
+ "bucket_versioning_disabled",
183
+ bucket=bucket_name,
184
+ status=versioning_status
185
+ )
186
+
187
+ except ClientError as e:
188
+ error_code = e.response.get("Error", {}).get("Code")
189
+ if error_code in ["NoSuchBucket", "AccessDenied"]:
190
+ self.logger.warning(
191
+ "bucket_versioning_check_error",
192
+ bucket=bucket_name,
193
+ error_code=error_code
194
+ )
195
+ continue
196
+ else:
197
+ raise
198
+
199
+ # Calculate compliance score
200
+ result.score = (versioning_enabled_count / len(buckets)) * 100
201
+
202
+ # Determine pass/fail
203
+ result.passed = versioning_enabled_count == len(buckets)
204
+ result.status = TestStatus.PASSED if result.passed else TestStatus.FAILED
205
+
206
+ # Add metadata
207
+ result.metadata = {
208
+ "total_buckets": len(buckets),
209
+ "versioning_enabled": versioning_enabled_count,
210
+ "versioning_disabled": len(buckets) - versioning_enabled_count,
211
+ "compliance_percentage": result.score,
212
+ }
213
+
214
+ self.logger.info(
215
+ "s3_versioning_test_completed",
216
+ total_buckets=len(buckets),
217
+ versioning_enabled=versioning_enabled_count,
218
+ score=result.score,
219
+ passed=result.passed
220
+ )
221
+
222
+ except ClientError as e:
223
+ error_code = e.response.get("Error", {}).get("Code")
224
+ self.logger.error("s3_versioning_test_error", error_code=error_code, error=str(e))
225
+ result.status = TestStatus.ERROR
226
+ result.passed = False
227
+ result.score = 0.0
228
+ result.error_message = f"AWS API Error: {error_code} - {str(e)}"
229
+
230
+ except Exception as e:
231
+ self.logger.error("s3_versioning_test_error", error=str(e))
232
+ result.status = TestStatus.ERROR
233
+ result.passed = False
234
+ result.score = 0.0
235
+ result.error_message = str(e)
236
+
237
+ return result
238
+
239
+
240
+ # ============================================================================
241
+ # CONVENIENCE FUNCTION
242
+ # ============================================================================
243
+
244
+
245
+ def run_s3_versioning_test(connector: AWSConnector) -> TestResult:
246
+ """Run S3 bucket versioning compliance test.
247
+
248
+ Convenience function for running the test.
249
+
250
+ Args:
251
+ connector: AWS connector
252
+
253
+ Returns:
254
+ TestResult
255
+
256
+ Example:
257
+ >>> from complio.connectors.aws.client import AWSConnector
258
+ >>> connector = AWSConnector("production", "us-east-1")
259
+ >>> connector.connect()
260
+ >>> result = run_s3_versioning_test(connector)
261
+ >>> print(f"Score: {result.score}%")
262
+ """
263
+ test = S3VersioningTest(connector)
264
+ return test.execute()
@@ -0,0 +1,26 @@
1
+ """Utility modules for Complio."""
2
+
3
+ from complio.utils.exceptions import (
4
+ AWSConnectionError,
5
+ AWSCredentialsError,
6
+ AWSError,
7
+ ComplioError,
8
+ InvalidRegionError,
9
+ ValidationError,
10
+ )
11
+ from complio.utils.logger import get_logger, setup_logging
12
+
13
+ __all__ = [
14
+ # Logging
15
+ "get_logger",
16
+ "setup_logging",
17
+ # Exceptions - Base
18
+ "ComplioError",
19
+ "AWSError",
20
+ # Exceptions - AWS
21
+ "AWSConnectionError",
22
+ "AWSCredentialsError",
23
+ "InvalidRegionError",
24
+ # Exceptions - Validation
25
+ "ValidationError",
26
+ ]
@@ -0,0 +1,179 @@
1
+ """
2
+ User-friendly error message translation for Complio.
3
+
4
+ This module translates technical AWS and system errors into actionable,
5
+ user-friendly messages with clear next steps.
6
+
7
+ Example:
8
+ >>> from complio.utils.errors import handle_aws_error
9
+ >>> try:
10
+ >>> connector.connect()
11
+ >>> except Exception as e:
12
+ >>> handle_aws_error(e)
13
+ """
14
+
15
+ import configparser
16
+ import os
17
+ import sys
18
+ from typing import NoReturn
19
+
20
+ import click
21
+ from botocore.exceptions import (
22
+ ClientError,
23
+ EndpointConnectionError,
24
+ NoCredentialsError,
25
+ PartialCredentialsError,
26
+ ProfileNotFound,
27
+ )
28
+
29
+
30
+ def handle_aws_error(error: Exception) -> NoReturn:
31
+ """Translate technical AWS errors to user-friendly messages.
32
+
33
+ This function catches common AWS errors and displays helpful messages
34
+ with actionable next steps instead of technical stack traces.
35
+
36
+ Args:
37
+ error: The exception that was raised
38
+
39
+ Raises:
40
+ SystemExit: Always exits with code 1 after displaying the error
41
+
42
+ Example:
43
+ >>> try:
44
+ >>> session = boto3.Session(profile_name="nonexistent")
45
+ >>> except Exception as e:
46
+ >>> handle_aws_error(e)
47
+ >>> # Displays: "❌ AWS profile 'nonexistent' not found"
48
+ >>> # Then lists available profiles
49
+ """
50
+
51
+ if isinstance(error, NoCredentialsError):
52
+ click.echo("❌ AWS credentials not found", err=True)
53
+ click.echo("\nTo configure AWS credentials:", err=True)
54
+ click.echo(" 1. Run: aws configure", err=True)
55
+ click.echo(" 2. Enter your Access Key ID and Secret Access Key", err=True)
56
+ click.echo("\nFor help: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html", err=True)
57
+ sys.exit(1)
58
+
59
+ elif isinstance(error, PartialCredentialsError):
60
+ click.echo("❌ Incomplete AWS credentials", err=True)
61
+ click.echo("\nYour AWS credentials are missing required information.", err=True)
62
+ click.echo("Run: aws configure", err=True)
63
+ sys.exit(1)
64
+
65
+ elif isinstance(error, ProfileNotFound):
66
+ # Extract profile name from error message
67
+ profile = str(error).split("'")[1] if "'" in str(error) else "unknown"
68
+ click.echo(f"❌ AWS profile '{profile}' not found", err=True)
69
+ click.echo(f"\nAvailable profiles in ~/.aws/credentials:", err=True)
70
+ try:
71
+ config = configparser.ConfigParser()
72
+ config.read(os.path.expanduser('~/.aws/credentials'))
73
+ if config.sections():
74
+ for prof in config.sections():
75
+ click.echo(f" • {prof}", err=True)
76
+ else:
77
+ click.echo(" (No profiles configured)", err=True)
78
+ click.echo("\nRun 'aws configure' to create a profile", err=True)
79
+ except Exception:
80
+ click.echo(" (Unable to read credentials file)", err=True)
81
+ sys.exit(1)
82
+
83
+ elif isinstance(error, EndpointConnectionError):
84
+ click.echo("❌ Cannot connect to AWS", err=True)
85
+ click.echo("\nPossible causes:", err=True)
86
+ click.echo(" • No internet connection", err=True)
87
+ click.echo(" • Invalid region specified", err=True)
88
+ click.echo(" • Corporate firewall blocking AWS", err=True)
89
+ sys.exit(1)
90
+
91
+ elif isinstance(error, ClientError):
92
+ error_code = error.response.get('Error', {}).get('Code', 'Unknown')
93
+ error_message = error.response.get('Error', {}).get('Message', '')
94
+
95
+ if error_code == 'UnauthorizedOperation':
96
+ click.echo("❌ Insufficient AWS permissions", err=True)
97
+ click.echo("\nYour AWS user needs the 'SecurityAudit' policy.", err=True)
98
+ click.echo("Contact your AWS administrator to grant permissions.", err=True)
99
+
100
+ elif error_code == 'InvalidClientTokenId':
101
+ click.echo("❌ Invalid AWS credentials", err=True)
102
+ click.echo("\nYour Access Key ID is not recognized by AWS.", err=True)
103
+ click.echo("Run 'aws configure' to update your credentials.", err=True)
104
+
105
+ elif error_code == 'SignatureDoesNotMatch':
106
+ click.echo("❌ Invalid AWS credentials", err=True)
107
+ click.echo("\nYour Secret Access Key is incorrect.", err=True)
108
+ click.echo("Run 'aws configure' to update your credentials.", err=True)
109
+
110
+ elif error_code == 'AccessDenied':
111
+ click.echo("❌ Access denied", err=True)
112
+ click.echo(f"\n{error_message}", err=True)
113
+ click.echo("\nYour AWS user needs additional permissions.", err=True)
114
+ click.echo("Contact your AWS administrator.", err=True)
115
+
116
+ elif error_code == 'InvalidRegion':
117
+ click.echo("❌ Invalid AWS region", err=True)
118
+ click.echo("\nValid regions: us-east-1, eu-west-1, eu-west-3, etc.", err=True)
119
+
120
+ else:
121
+ click.echo(f"❌ AWS Error: {error_code}", err=True)
122
+ if error_message:
123
+ click.echo(f"\n{error_message}", err=True)
124
+ click.echo(f"\nFor help: https://docs.complio.tech/errors", err=True)
125
+
126
+ sys.exit(1)
127
+
128
+ else:
129
+ # Unknown error - show technical message but add help
130
+ click.echo(f"❌ Unexpected error: {str(error)}", err=True)
131
+ click.echo(f"\nFor help: https://docs.complio.tech/troubleshooting", err=True)
132
+ click.echo(f"Support: support@complio.tech", err=True)
133
+ sys.exit(1)
134
+
135
+
136
+ def validate_region_format(region: str) -> bool:
137
+ """Validate AWS region format.
138
+
139
+ Args:
140
+ region: Region string to validate
141
+
142
+ Returns:
143
+ True if valid format, False otherwise
144
+
145
+ Example:
146
+ >>> validate_region_format("us-east-1")
147
+ True
148
+ >>> validate_region_format("invalid")
149
+ False
150
+ """
151
+ import re
152
+ # AWS region format: 2 letters, dash, direction/location, dash, number
153
+ # Examples: us-east-1, eu-west-3, ap-southeast-2
154
+ pattern = r'^[a-z]{2}-[a-z]+-\d+$'
155
+ return bool(re.match(pattern, region))
156
+
157
+
158
+ def validate_profile_exists(profile: str) -> bool:
159
+ """Check if AWS profile exists in credentials file.
160
+
161
+ Args:
162
+ profile: Profile name to check
163
+
164
+ Returns:
165
+ True if profile exists, False otherwise
166
+
167
+ Example:
168
+ >>> validate_profile_exists("default")
169
+ True
170
+ """
171
+ if profile == "default":
172
+ return True # Default profile is implicit
173
+
174
+ try:
175
+ config = configparser.ConfigParser()
176
+ config.read(os.path.expanduser('~/.aws/credentials'))
177
+ return profile in config.sections()
178
+ except Exception:
179
+ return True # If can't read file, let boto3 handle it
@@ -0,0 +1,151 @@
1
+ """
2
+ Custom exceptions for Complio.
3
+
4
+ This module defines all custom exceptions used throughout the application.
5
+ All exceptions inherit from ComplioError for easy catching of all application errors.
6
+ """
7
+
8
+ from typing import Optional
9
+
10
+
11
+ class ComplioError(Exception):
12
+ """Base exception for all Complio errors.
13
+
14
+ All custom exceptions should inherit from this class to allow
15
+ catching all application-specific errors.
16
+ """
17
+
18
+ def __init__(self, message: str, details: Optional[dict[str, str]] = None) -> None:
19
+ """Initialize ComplioError.
20
+
21
+ Args:
22
+ message: Human-readable error message
23
+ details: Optional dictionary with additional error context
24
+ """
25
+ super().__init__(message)
26
+ self.message = message
27
+ self.details = details or {}
28
+
29
+
30
+ class CryptoError(ComplioError):
31
+ """Base exception for cryptography-related errors."""
32
+ pass
33
+
34
+
35
+ class EncryptionError(CryptoError):
36
+ """Raised when encryption operations fail.
37
+
38
+ Examples:
39
+ - Encryption algorithm failure
40
+ - Invalid encryption key
41
+ - Corrupted data during encryption
42
+ """
43
+ pass
44
+
45
+
46
+ class DecryptionError(CryptoError):
47
+ """Raised when decryption operations fail.
48
+
49
+ Examples:
50
+ - Invalid decryption key (wrong password)
51
+ - Corrupted encrypted data
52
+ - Tampered encrypted file
53
+ - Invalid token format
54
+ """
55
+ pass
56
+
57
+
58
+ class CredentialError(ComplioError):
59
+ """Base exception for credential-related errors."""
60
+ pass
61
+
62
+
63
+ class InvalidCredentialsError(CredentialError):
64
+ """Raised when AWS credentials are invalid or malformed.
65
+
66
+ Examples:
67
+ - Empty access key or secret key
68
+ - Invalid access key format (not AKIA...)
69
+ - Credentials that don't match AWS format requirements
70
+ """
71
+ pass
72
+
73
+
74
+ class CredentialStorageError(CredentialError):
75
+ """Raised when credential storage operations fail.
76
+
77
+ Examples:
78
+ - Unable to create credentials directory
79
+ - Insufficient permissions to write credentials file
80
+ - Disk full when saving credentials
81
+ """
82
+ pass
83
+
84
+
85
+ class CredentialNotFoundError(CredentialError):
86
+ """Raised when attempting to load non-existent credentials.
87
+
88
+ Examples:
89
+ - Credentials file doesn't exist
90
+ - Profile name not found in credentials file
91
+ """
92
+ pass
93
+
94
+
95
+ class InvalidPasswordError(CredentialError):
96
+ """Raised when password validation fails.
97
+
98
+ Examples:
99
+ - Password too short (< 8 characters)
100
+ - Password doesn't meet complexity requirements
101
+ - Wrong password during decryption
102
+ """
103
+ pass
104
+
105
+
106
+ class ValidationError(ComplioError):
107
+ """Raised when input validation fails.
108
+
109
+ Examples:
110
+ - Invalid AWS region
111
+ - Malformed account ID
112
+ - Invalid file path
113
+ """
114
+ pass
115
+
116
+
117
+ class AWSError(ComplioError):
118
+ """Base exception for AWS-related errors."""
119
+ pass
120
+
121
+
122
+ class AWSCredentialsError(AWSError):
123
+ """Raised when AWS API rejects credentials.
124
+
125
+ Examples:
126
+ - Invalid access key or secret key
127
+ - Expired temporary credentials
128
+ - Insufficient IAM permissions
129
+ """
130
+ pass
131
+
132
+
133
+ class AWSConnectionError(AWSError):
134
+ """Raised when unable to connect to AWS API.
135
+
136
+ Examples:
137
+ - Network timeout
138
+ - DNS resolution failure
139
+ - AWS service unavailable
140
+ """
141
+ pass
142
+
143
+
144
+ class InvalidRegionError(AWSError):
145
+ """Raised when AWS region is invalid.
146
+
147
+ Examples:
148
+ - Non-existent region name
149
+ - Region not enabled for account
150
+ """
151
+ pass