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
complio/cli/main.py ADDED
@@ -0,0 +1,115 @@
1
+ """
2
+ Complio CLI - Main entry point.
3
+
4
+ This module defines the main CLI application and command groups.
5
+ """
6
+
7
+ import sys
8
+
9
+ import click
10
+
11
+ from complio.cli import output
12
+ from complio.cli.banner import print_banner
13
+
14
+ # CLI version (sync with pyproject.toml)
15
+ VERSION = "0.1.0"
16
+
17
+
18
+ # ============================================================================
19
+ # MAIN CLI GROUP
20
+ # ============================================================================
21
+
22
+
23
+ @click.group(invoke_without_command=True)
24
+ @click.version_option(version=VERSION, prog_name="complio")
25
+ @click.pass_context
26
+ def cli(ctx: click.Context) -> None:
27
+ """
28
+ 🔒 Complio - ISO 27001 Compliance Scanner for AWS
29
+
30
+ Automated compliance testing against ISO 27001:2022 controls.
31
+ 40 tests covering encryption, network, IAM, and logging.
32
+
33
+ \b
34
+ Prerequisites:
35
+ AWS CLI configured: aws configure
36
+
37
+ \b
38
+ Quick Start:
39
+ complio scan # Scan with default profile
40
+ complio scan --region eu-west-3 # Specific region
41
+ complio scan --profile production # Specific AWS profile
42
+
43
+ \b
44
+ Commands:
45
+ scan Run ISO 27001 compliance tests
46
+ history View past scan results
47
+ compare Compare two scans
48
+ clear-history Clear scan history
49
+
50
+ \b
51
+ Examples:
52
+ # Run compliance scan
53
+ complio scan
54
+
55
+ # View scan history
56
+ complio history
57
+
58
+ # Compare two scans
59
+ complio compare scan-123 scan-456
60
+
61
+ Documentation: https://github.com/Tiger972/complio
62
+ """
63
+ # Ensure context object exists
64
+ ctx.ensure_object(dict)
65
+
66
+ # Show banner when no subcommand is provided
67
+ if ctx.invoked_subcommand is None:
68
+ print_banner()
69
+ output.print_message("")
70
+ click.echo(ctx.get_help())
71
+
72
+
73
+ # ============================================================================
74
+ # SCAN COMMAND
75
+ # ============================================================================
76
+
77
+ from complio.cli.commands.scan import scan
78
+
79
+ cli.add_command(scan)
80
+
81
+
82
+ # ============================================================================
83
+ # HISTORY COMMANDS
84
+ # ============================================================================
85
+
86
+ from complio.cli.commands.history import history, compare, clear_history_cmd
87
+
88
+ cli.add_command(history)
89
+ cli.add_command(compare)
90
+ cli.add_command(clear_history_cmd)
91
+
92
+
93
+ # ============================================================================
94
+ # MAIN ENTRY POINT
95
+ # ============================================================================
96
+
97
+
98
+ def main() -> None:
99
+ """Main entry point for CLI."""
100
+ try:
101
+ cli()
102
+ except KeyboardInterrupt:
103
+ output.print_message("\n")
104
+ output.warning("Operation cancelled by user")
105
+ sys.exit(130)
106
+ except Exception as e:
107
+ output.error(
108
+ "Unexpected error",
109
+ f"{type(e).__name__}: {str(e)}",
110
+ )
111
+ sys.exit(1)
112
+
113
+
114
+ if __name__ == "__main__":
115
+ main()
complio/cli/output.py ADDED
@@ -0,0 +1,338 @@
1
+ """
2
+ CLI output formatting utilities.
3
+
4
+ This module provides rich, user-friendly terminal output using the Rich library.
5
+ Includes formatted messages for success, errors, warnings, and information.
6
+
7
+ Features:
8
+ - Color-coded output (green=success, red=error, yellow=warning, blue=info)
9
+ - Styled tables for structured data
10
+ - Progress indicators
11
+ - Panels for grouped information
12
+ - Consistent formatting across all CLI commands
13
+ """
14
+
15
+ from typing import Any, Optional
16
+
17
+ from rich.console import Console
18
+ from rich.panel import Panel
19
+ from rich.table import Table
20
+ from rich.text import Text
21
+
22
+ # Initialize Rich console for styled output
23
+ console = Console()
24
+
25
+
26
+ # ============================================================================
27
+ # OUTPUT FUNCTIONS
28
+ # ============================================================================
29
+
30
+
31
+ def success(message: str, detail: Optional[str] = None) -> None:
32
+ """Print success message in green.
33
+
34
+ Args:
35
+ message: Main success message
36
+ detail: Optional additional detail to display below message
37
+
38
+ Example:
39
+ >>> success("Credentials encrypted successfully", "Profile: production")
40
+ ✓ Credentials encrypted successfully
41
+ Profile: production
42
+ """
43
+ text = Text()
44
+ text.append("✓ ", style="bold green")
45
+ text.append(message, style="green")
46
+ console.print(text)
47
+
48
+ if detail:
49
+ console.print(f" {detail}", style="dim green")
50
+
51
+
52
+ def error(message: str, detail: Optional[str] = None, exit_code: int = 1) -> None:
53
+ """Print error message in red and exit.
54
+
55
+ Args:
56
+ message: Main error message
57
+ detail: Optional additional detail (e.g., exception message)
58
+ exit_code: Exit code (default: 1)
59
+
60
+ Example:
61
+ >>> error("Failed to decrypt credentials", "Invalid password")
62
+ ✗ Failed to decrypt credentials
63
+ Invalid password
64
+ [Exits with code 1]
65
+ """
66
+ text = Text()
67
+ text.append("✗ ", style="bold red")
68
+ text.append(message, style="red")
69
+ console.print(text)
70
+
71
+ if detail:
72
+ console.print(f" {detail}", style="dim red")
73
+
74
+ raise SystemExit(exit_code)
75
+
76
+
77
+ def warning(message: str, detail: Optional[str] = None) -> None:
78
+ """Print warning message in yellow.
79
+
80
+ Args:
81
+ message: Main warning message
82
+ detail: Optional additional detail
83
+
84
+ Example:
85
+ >>> warning("Profile already exists", "Will overwrite existing credentials")
86
+ ⚠ Profile already exists
87
+ Will overwrite existing credentials
88
+ """
89
+ text = Text()
90
+ text.append("⚠ ", style="bold yellow")
91
+ text.append(message, style="yellow")
92
+ console.print(text)
93
+
94
+ if detail:
95
+ console.print(f" {detail}", style="dim yellow")
96
+
97
+
98
+ def info(message: str, detail: Optional[str] = None) -> None:
99
+ """Print info message in blue.
100
+
101
+ Args:
102
+ message: Main info message
103
+ detail: Optional additional detail
104
+
105
+ Example:
106
+ >>> info("Loading credentials", "Profile: production")
107
+ ℹ Loading credentials
108
+ Profile: production
109
+ """
110
+ text = Text()
111
+ text.append("ℹ ", style="bold blue")
112
+ text.append(message, style="blue")
113
+ console.print(text)
114
+
115
+ if detail:
116
+ console.print(f" {detail}", style="dim blue")
117
+
118
+
119
+ def print_message(message: str, style: str = "") -> None:
120
+ """Print plain message with optional style.
121
+
122
+ Args:
123
+ message: Message to print
124
+ style: Optional Rich style string (e.g., "bold", "dim", "cyan")
125
+
126
+ Example:
127
+ >>> print_message("Processing...", style="dim")
128
+ Processing...
129
+ """
130
+ console.print(message, style=style)
131
+
132
+
133
+ def print_panel(
134
+ title: str,
135
+ content: str,
136
+ style: str = "blue",
137
+ border_style: str = "blue",
138
+ ) -> None:
139
+ """Print content in a styled panel.
140
+
141
+ Args:
142
+ title: Panel title
143
+ content: Panel content
144
+ style: Content text style
145
+ border_style: Border color style
146
+
147
+ Example:
148
+ >>> print_panel("Configuration", "Region: eu-west-1\\nProfile: prod", style="cyan")
149
+ ╭─── Configuration ────╮
150
+ │ Region: eu-west-1 │
151
+ │ Profile: prod │
152
+ ╰──────────────────────╯
153
+ """
154
+ panel = Panel(
155
+ content,
156
+ title=title,
157
+ border_style=border_style,
158
+ title_align="left",
159
+ )
160
+ console.print(panel)
161
+
162
+
163
+ def print_table(
164
+ title: str,
165
+ headers: list[str],
166
+ rows: list[list[str]],
167
+ caption: Optional[str] = None,
168
+ ) -> None:
169
+ """Print data in a formatted table.
170
+
171
+ Args:
172
+ title: Table title
173
+ headers: Column headers
174
+ rows: Table rows (list of lists)
175
+ caption: Optional table caption/footer
176
+
177
+ Example:
178
+ >>> print_table(
179
+ ... "Stored Profiles",
180
+ ... ["Profile", "Created"],
181
+ ... [["production", "2024-01-15"], ["staging", "2024-01-16"]]
182
+ ... )
183
+ ┏━━━━━━━━━━━┳━━━━━━━━━━━━┓
184
+ ┃ Profile ┃ Created ┃
185
+ ┡━━━━━━━━━━━╇━━━━━━━━━━━━┩
186
+ │ production│ 2024-01-15 │
187
+ │ staging │ 2024-01-16 │
188
+ └───────────┴────────────┘
189
+ """
190
+ table = Table(title=title, caption=caption, show_header=True, header_style="bold cyan")
191
+
192
+ # Add columns
193
+ for header in headers:
194
+ table.add_column(header, style="white")
195
+
196
+ # Add rows
197
+ for row in rows:
198
+ table.add_row(*row)
199
+
200
+ console.print(table)
201
+
202
+
203
+ def print_separator(char: str = "─", length: int = 60) -> None:
204
+ """Print a horizontal separator line.
205
+
206
+ Args:
207
+ char: Character to use for separator
208
+ length: Length of separator
209
+
210
+ Example:
211
+ >>> print_separator()
212
+ ────────────────────────────────────────────────────────────
213
+ """
214
+ console.print(char * length, style="dim")
215
+
216
+
217
+ def print_header(title: str) -> None:
218
+ """Print a formatted section header.
219
+
220
+ Args:
221
+ title: Header title
222
+
223
+ Example:
224
+ >>> print_header("Credential Configuration")
225
+
226
+ ═══════════════════════════════════════════
227
+ Credential Configuration
228
+ ═══════════════════════════════════════════
229
+ """
230
+ console.print()
231
+ console.print("═" * 60, style="cyan")
232
+ console.print(f" {title}", style="bold cyan")
233
+ console.print("═" * 60, style="cyan")
234
+ console.print()
235
+
236
+
237
+ def confirm(message: str, default: bool = False) -> bool:
238
+ """Prompt user for yes/no confirmation.
239
+
240
+ Args:
241
+ message: Confirmation question
242
+ default: Default value if user just presses Enter
243
+
244
+ Returns:
245
+ True if user confirms, False otherwise
246
+
247
+ Example:
248
+ >>> if confirm("Delete profile 'production'?"):
249
+ ... print("Deleting...")
250
+ Delete profile 'production'? [y/N]: y
251
+ Deleting...
252
+ """
253
+ suffix = " [Y/n]: " if default else " [y/N]: "
254
+ response = console.input(f"[yellow]{message}{suffix}[/yellow]").strip().lower()
255
+
256
+ if not response:
257
+ return default
258
+
259
+ return response in ("y", "yes")
260
+
261
+
262
+ def prompt(message: str, default: Optional[str] = None, password: bool = False) -> str:
263
+ """Prompt user for input.
264
+
265
+ Args:
266
+ message: Prompt message
267
+ default: Default value if user just presses Enter
268
+ password: If True, hide input (for passwords)
269
+
270
+ Returns:
271
+ User input string
272
+
273
+ Example:
274
+ >>> name = prompt("Enter profile name", default="default")
275
+ Enter profile name [default]: production
276
+ >>> # Returns: "production"
277
+ """
278
+ suffix = f" [{default}]: " if default else ": "
279
+ prompt_text = f"[cyan]{message}{suffix}[/cyan]"
280
+
281
+ if password:
282
+ response = console.input(prompt_text, password=True).strip()
283
+ else:
284
+ response = console.input(prompt_text).strip()
285
+
286
+ if not response and default:
287
+ return default
288
+
289
+ return response
290
+
291
+
292
+ # ============================================================================
293
+ # OUTPUT HELPER CLASS (FOR COMPATIBILITY)
294
+ # ============================================================================
295
+
296
+
297
+ class ComplianceOutput:
298
+ """
299
+ Helper class for output operations.
300
+
301
+ This class wraps the module-level output functions in a class interface
302
+ for convenience and compatibility with existing code.
303
+ """
304
+
305
+ @staticmethod
306
+ def success(message: str, detail: Optional[str] = None) -> None:
307
+ """Print success message."""
308
+ success(message, detail)
309
+
310
+ @staticmethod
311
+ def error(message: str, detail: Optional[str] = None, exit_code: int = 1) -> None:
312
+ """Print error message."""
313
+ error(message, detail, exit_code)
314
+
315
+ @staticmethod
316
+ def warning(message: str, detail: Optional[str] = None) -> None:
317
+ """Print warning message."""
318
+ warning(message, detail)
319
+
320
+ @staticmethod
321
+ def info(message: str, detail: Optional[str] = None) -> None:
322
+ """Print info message."""
323
+ info(message, detail)
324
+
325
+ @staticmethod
326
+ def print_message(message: str, style: str = "") -> None:
327
+ """Print plain message."""
328
+ print_message(message, style)
329
+
330
+ @staticmethod
331
+ def prompt(message: str, default: Optional[str] = None) -> str:
332
+ """Prompt user for input."""
333
+ return prompt(message, default, password=False)
334
+
335
+ @staticmethod
336
+ def prompt_password(message: str) -> str:
337
+ """Prompt user for password (hidden input)."""
338
+ return prompt(message, password=True)
@@ -0,0 +1,17 @@
1
+ """Configuration management for Complio."""
2
+
3
+ from complio.config.settings import (
4
+ ComplioSettings,
5
+ VALID_AWS_REGIONS,
6
+ VALID_LOG_LEVELS,
7
+ VALID_OUTPUT_FORMATS,
8
+ get_settings,
9
+ )
10
+
11
+ __all__ = [
12
+ "ComplioSettings",
13
+ "get_settings",
14
+ "VALID_AWS_REGIONS",
15
+ "VALID_LOG_LEVELS",
16
+ "VALID_OUTPUT_FORMATS",
17
+ ]