-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudit.py
More file actions
executable file
·156 lines (132 loc) · 4.69 KB
/
Copy pathaudit.py
File metadata and controls
executable file
·156 lines (132 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
"""
Full infrastructure audit for Docker Compose stacks.
Combines validation, port analysis, and image audit into a comprehensive report.
Usage:
./scripts/audit.py # Full audit, JSON output
./scripts/audit.py --human # Human-readable output
./scripts/audit.py --ports # Port analysis only
./scripts/audit.py --images # Image audit only
"""
from __future__ import annotations
import argparse
import sys
from datetime import datetime
from pathlib import Path
# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent))
from lib.discovery import find_project_root
from lib.validator import validate_all_stacks
from lib.ports import analyze_all_ports, get_port_summary
from lib.images import analyze_all_images, get_image_summary
from lib.report import generate_audit_report, HumanReporter, write_json
from lib.models import AuditReport, to_json
def main() -> int:
parser = argparse.ArgumentParser(
description="Full infrastructure audit for Docker Compose stacks",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s Full audit (JSON output)
%(prog)s --human Human-readable output
%(prog)s --ports Port analysis only
%(prog)s --images Image audit only
%(prog)s --summary Summary statistics only
""",
)
parser.add_argument(
"--human",
action="store_true",
help="Output human-readable format instead of JSON",
)
parser.add_argument(
"--ports",
action="store_true",
help="Run port analysis only",
)
parser.add_argument(
"--images",
action="store_true",
help="Run image audit only",
)
parser.add_argument(
"--validate",
action="store_true",
help="Run validation only",
)
parser.add_argument(
"--summary",
action="store_true",
help="Output only summary statistics",
)
parser.add_argument(
"--root",
type=Path,
help="Project root directory (auto-detected if not specified)",
)
args = parser.parse_args()
# Determine project root
root = args.root or find_project_root()
try:
# Determine which audits to run
run_all = not (args.ports or args.images or args.validate)
# Run requested audits
validations = None
port_analysis = None
image_audit = None
if run_all or args.validate:
validations = validate_all_stacks(root)
if run_all or args.ports:
port_analysis = analyze_all_ports(root)
if run_all or args.images:
image_audit = analyze_all_images(root)
# Handle single-audit modes
if args.ports and not run_all:
if args.summary:
print(to_json(get_port_summary(port_analysis)))
elif args.human:
reporter = HumanReporter()
reporter.report_ports(port_analysis)
else:
print(to_json(get_port_summary(port_analysis)))
return 1 if port_analysis.has_conflicts else 0
if args.images and not run_all:
if args.summary:
print(to_json(get_image_summary(image_audit)))
elif args.human:
reporter = HumanReporter()
reporter.report_images(image_audit)
else:
print(to_json(get_image_summary(image_audit)))
return 0
if args.validate and not run_all:
from lib.report import generate_validation_report
generate_validation_report(validations, output_json=not args.human, file=sys.stdout)
total_errors = sum(v.errors for v in validations)
return 1 if total_errors > 0 else 0
# Full audit report
report = AuditReport(
timestamp=datetime.now(),
project_root=str(root),
validations=validations or [],
port_analysis=port_analysis,
image_audit=image_audit,
)
if args.summary:
print(to_json(report.summary()))
else:
generate_audit_report(report, output_json=not args.human, file=sys.stdout)
# Exit code
has_errors = (
(validations and sum(v.errors for v in validations) > 0)
or (port_analysis and port_analysis.has_conflicts)
)
return 1 if has_errors else 0
except Exception as e:
if args.human:
print(f"Error: {e}", file=sys.stderr)
else:
print(to_json({"error": str(e)}))
return 1
if __name__ == "__main__":
sys.exit(main())