reconpro 2.0.0__tar.gz

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.
reconpro-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ReconPro Security
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.4
2
+ Name: reconpro
3
+ Version: 2.0.0
4
+ Summary: ReconPro Enterprise — The Security Reconnaissance Platform. Eight Blades. One Target. One Verdict.
5
+ Home-page: https://github.com/reconpro-security/reconpro
6
+ Author: ReconPro Security
7
+ Author-email: ReconPro Security <security@reconpro.io>
8
+ License-Expression: MIT
9
+ Keywords: security,scanner,reconnaissance,vulnerability,reconpro,vibesec,pentest,red-team,auth-bypass,ssrf,bot-detection,nhi,cloud-security
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Security
17
+ Classifier: Topic :: Software Development :: Testing
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: rich>=13.0.0
22
+ Dynamic: author
23
+ Dynamic: home-page
24
+ Dynamic: license-file
25
+ Dynamic: requires-python
26
+
27
+ # ReconPro Enterprise
28
+
29
+ > **Eight Blades. One Target. One Verdict.**
30
+
31
+ The full-spectrum security reconnaissance platform. 8 scanning modules, one CLI command.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install reconpro
37
+ ```
38
+
39
+ Or from source:
40
+
41
+ ```bash
42
+ git clone https://github.com/reconpro-security/reconpro.git
43
+ cd reconpro
44
+ pip install .
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ ```bash
50
+ # Scan with default modules (recon, vibesec, auth, chain, oblivion)
51
+ reconpro example.com
52
+
53
+ # Run all 8 modules
54
+ reconpro example.com --all
55
+
56
+ # Pick specific modules
57
+ reconpro example.com --modules recon,auth,nhi
58
+
59
+ # Quick VibeSec benchmark only
60
+ reconpro vibesec example.com
61
+
62
+ # JSON output
63
+ reconpro example.com --json -o report.json
64
+
65
+ # Skip TLS verification
66
+ reconpro example.com --insecure
67
+
68
+ # Adjust timeout and rate limit
69
+ reconpro example.com --timeout 5 --rate-limit 5
70
+ ```
71
+
72
+ ## Modules
73
+
74
+ | Module | ID | Description |
75
+ |--------|----|-------------|
76
+ | **RECON** | `recon` | 13-category surface reconnaissance (DNS, ports, TLS, headers, tech, WAF, cookies, CORS) |
77
+ | **AUTH BYPASS** | `auth` | 15 auth bypass techniques (header injection, method tampering, path traversal, IDOR) |
78
+ | **CHAIN HUNTER** | `chain` | SSRF + redirect chain hunting (cloud metadata, open redirects) |
79
+ | **BOT HUNTER** | `bot` | C2 / bot infrastructure detection + honeypot identification |
80
+ | **GORGON ULTRA** | `gorgon` | AI red team (SQLi, XSS, path traversal, HTTP methods, content-type) |
81
+ | **OBLIVION** | `oblivion` | 23-stage deep analysis with DREAD scoring (info disclosure, JS secrets, deep headers) |
82
+ | **VIBESEC** | `vibesec` | AI/vibe-coding vulnerability benchmark (100-point score, A+–F grades, GitHub badge) |
83
+ | **NHI GRAPH** | `nhi` | Non-Human Identity detection (cloud metadata SSRF, leaked tokens, credential files) |
84
+
85
+ ## Scoring
86
+
87
+ - **100-point** benchmark system
88
+ - **A+** (90+) → **F** (0–34) grades
89
+ - GitHub-ready **badge** for your README
90
+ - Per-module breakdowns with severity counts
91
+
92
+ ## Output
93
+
94
+ Rich terminal UI with:
95
+ - Color-coded severity tables
96
+ - Module-by-module breakdown
97
+ - Progress spinners
98
+ - Score bars and grade indicators
99
+ - JSON export for CI/CD integration
100
+
101
+ ## Requirements
102
+
103
+ - Python 3.8+
104
+ - No other dependencies (stdlib-only networking)
105
+ - `rich` for terminal UI (auto-installed)
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,83 @@
1
+ # ReconPro Enterprise
2
+
3
+ > **Eight Blades. One Target. One Verdict.**
4
+
5
+ The full-spectrum security reconnaissance platform. 8 scanning modules, one CLI command.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install reconpro
11
+ ```
12
+
13
+ Or from source:
14
+
15
+ ```bash
16
+ git clone https://github.com/reconpro-security/reconpro.git
17
+ cd reconpro
18
+ pip install .
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```bash
24
+ # Scan with default modules (recon, vibesec, auth, chain, oblivion)
25
+ reconpro example.com
26
+
27
+ # Run all 8 modules
28
+ reconpro example.com --all
29
+
30
+ # Pick specific modules
31
+ reconpro example.com --modules recon,auth,nhi
32
+
33
+ # Quick VibeSec benchmark only
34
+ reconpro vibesec example.com
35
+
36
+ # JSON output
37
+ reconpro example.com --json -o report.json
38
+
39
+ # Skip TLS verification
40
+ reconpro example.com --insecure
41
+
42
+ # Adjust timeout and rate limit
43
+ reconpro example.com --timeout 5 --rate-limit 5
44
+ ```
45
+
46
+ ## Modules
47
+
48
+ | Module | ID | Description |
49
+ |--------|----|-------------|
50
+ | **RECON** | `recon` | 13-category surface reconnaissance (DNS, ports, TLS, headers, tech, WAF, cookies, CORS) |
51
+ | **AUTH BYPASS** | `auth` | 15 auth bypass techniques (header injection, method tampering, path traversal, IDOR) |
52
+ | **CHAIN HUNTER** | `chain` | SSRF + redirect chain hunting (cloud metadata, open redirects) |
53
+ | **BOT HUNTER** | `bot` | C2 / bot infrastructure detection + honeypot identification |
54
+ | **GORGON ULTRA** | `gorgon` | AI red team (SQLi, XSS, path traversal, HTTP methods, content-type) |
55
+ | **OBLIVION** | `oblivion` | 23-stage deep analysis with DREAD scoring (info disclosure, JS secrets, deep headers) |
56
+ | **VIBESEC** | `vibesec` | AI/vibe-coding vulnerability benchmark (100-point score, A+–F grades, GitHub badge) |
57
+ | **NHI GRAPH** | `nhi` | Non-Human Identity detection (cloud metadata SSRF, leaked tokens, credential files) |
58
+
59
+ ## Scoring
60
+
61
+ - **100-point** benchmark system
62
+ - **A+** (90+) → **F** (0–34) grades
63
+ - GitHub-ready **badge** for your README
64
+ - Per-module breakdowns with severity counts
65
+
66
+ ## Output
67
+
68
+ Rich terminal UI with:
69
+ - Color-coded severity tables
70
+ - Module-by-module breakdown
71
+ - Progress spinners
72
+ - Score bars and grade indicators
73
+ - JSON export for CI/CD integration
74
+
75
+ ## Requirements
76
+
77
+ - Python 3.8+
78
+ - No other dependencies (stdlib-only networking)
79
+ - `rich` for terminal UI (auto-installed)
80
+
81
+ ## License
82
+
83
+ MIT
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "reconpro"
7
+ version = "2.0.0"
8
+ description = "ReconPro Enterprise — The Security Reconnaissance Platform. Eight Blades. One Target. One Verdict."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ {name = "ReconPro Security", email = "security@reconpro.io"},
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Information Technology",
20
+ "Intended Audience :: System Administrators",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Security",
23
+ "Topic :: Software Development :: Testing",
24
+ ]
25
+ keywords = [
26
+ "security", "scanner", "reconnaissance", "vulnerability",
27
+ "reconpro", "vibesec", "pentest", "red-team", "auth-bypass",
28
+ "ssrf", "bot-detection", "nhi", "cloud-security",
29
+ ]
30
+ dependencies = [
31
+ "rich>=13.0.0",
32
+ ]
33
+
34
+ [project.scripts]
35
+ reconpro = "reconpro.cli:main"
36
+
37
+ [tool.setuptools]
38
+ packages = ["reconpro", "reconpro.modules"]
@@ -0,0 +1,25 @@
1
+ """ReconPro Enterprise — The Security Reconnaissance Platform.
2
+
3
+ Eight Blades. One Target. One Verdict.
4
+
5
+ Modules:
6
+ recon 13-category surface reconnaissance
7
+ auth 15 auth bypass techniques
8
+ chain SSRF + redirect chain hunting
9
+ bot C2 / bot infrastructure detection
10
+ gorgon 15-stage AI red team
11
+ oblivion 23-stage analytical dissolution
12
+ vibesec AI/vibe-coding vulnerability benchmark
13
+ nhi Non-Human Identity & blast-radius mapping
14
+
15
+ Usage:
16
+ reconpro example.com
17
+ reconpro example.com --modules recon,auth,vibesec
18
+ reconpro example.com --all --json -o report.json
19
+ reconpro vibesec example.com
20
+ """
21
+
22
+ __version__ = "2.0.0"
23
+ __all__ = ["scan", "ReconProResult", "__version__"]
24
+
25
+ from .scanner import scan, ReconProResult # noqa: E402
@@ -0,0 +1,338 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ import time
7
+
8
+ from rich.console import Console, Group
9
+ from rich.panel import Panel
10
+ from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
11
+ from rich.table import Table
12
+ from rich.text import Text
13
+ from rich.columns import Columns
14
+ from rich.rule import Rule
15
+
16
+ from . import __version__
17
+ from .scanner import scan, MODULE_REGISTRY, ALL_MODULES, DEFAULT_MODULES
18
+
19
+ console = Console()
20
+
21
+ BANNER = r"""[bold bright_white]
22
+ ██████╗ ███████╗ ██████╗██╗ ██╗███████╗██████╗ ███████╗██████╗ ██████╗ ██╗ ██╗
23
+ ██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔══██╗██╔════╝██╔════╝██║██╗ ██╔╝
24
+ ██████╔╝█████╗ ██║ ███████║█████╗ ██████╔╝█████╗ ██║ ██╔╝██╗██║
25
+ ██╔═══╝ ██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗██╔══╝ ██║ █████╔╝██║
26
+ ██║ ███████╗╚██████╗██║ ██║███████╗██║ ██║███████╗╚██████╗██╔╝██╗██║
27
+ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝
28
+ [/bold bright_white][dim] E I G H T B L A D E S . O N E T A R G E T . O N E V E R D I C T.[/dim]
29
+ """
30
+
31
+
32
+ SEV_COLORS = {
33
+ "critical": "bright_red",
34
+ "high": "red",
35
+ "medium": "yellow",
36
+ "low": "green",
37
+ "info": "dim",
38
+ }
39
+
40
+ GRADE_COLORS = {
41
+ "A+": "bright_green",
42
+ "A": "green",
43
+ "B": "yellow",
44
+ "C": "red",
45
+ "D": "bright_red",
46
+ "F": "bold bright_red",
47
+ }
48
+
49
+
50
+ # ── Rich rendering ──────────────────────────────────────────────────────
51
+
52
+
53
+ def _render_summary(result) -> None:
54
+ score = result.total_score
55
+ grade = result.grade
56
+ grade_color = GRADE_COLORS.get(grade, "bold bright_red")
57
+ sc = result.severity_counts
58
+ total = len(result.findings)
59
+
60
+ bar_width = 50
61
+ filled = int(score / 100 * bar_width)
62
+ bar = "█" * filled + "░" * (bar_width - filled)
63
+
64
+ console.print(Panel(
65
+ Group(
66
+ Text(f"\n {bar} [bold {grade_color}]{score}/100 ({grade})[/{grade_color}]"),
67
+ Text(f"\n Target: [cyan]{result.target}[/]"),
68
+ Text(f" Modules: [dim]{', '.join(result.modules_run)}[/]"),
69
+ Text(""),
70
+ Text(
71
+ f" Findings: [bold]{total}[/] "
72
+ f"[bright_red]{sc.get('critical', 0)} critical[/], "
73
+ f"[red]{sc.get('high', 0)} high[/], "
74
+ f"[yellow]{sc.get('medium', 0)} medium[/], "
75
+ f"[green]{sc.get('low', 0)} low[/], "
76
+ f"[dim]{sc.get('info', 0)} info[/]",
77
+ ),
78
+ *(
79
+ [Text(f"\n VibeSec Score: [bold bright_green]{result.vibesec_score}/100 ({result.vibesec_grade})[/]")]
80
+ if result.vibesec_score is not None else []
81
+ ),
82
+ ),
83
+ border_style=grade_color,
84
+ title="[bold]RECONPRO[/bold]",
85
+ title_align="left",
86
+ padding=(1, 2),
87
+ ))
88
+
89
+
90
+ def _render_findings_table(result) -> None:
91
+ if not result.findings:
92
+ console.print("\n [bright_green]No findings. Target is clean.[/]")
93
+ return
94
+
95
+ table = Table(
96
+ title=f"Findings — {len(result.findings)} detected",
97
+ border_style="bright_white",
98
+ header_style="bold bright_white",
99
+ show_lines=False,
100
+ )
101
+ table.add_column("Severity", style="bold", width=10)
102
+ table.add_column("Module", style="cyan", width=12)
103
+ table.add_column("Category", style="magenta", width=18)
104
+ table.add_column("Finding", style="white")
105
+ table.add_column("Pts", style="yellow", width=5)
106
+
107
+ for f in result.findings[:50]:
108
+ sev = f.get("severity", "info")
109
+ color = SEV_COLORS.get(sev, "white")
110
+ table.add_row(
111
+ f"[{color}]{sev.upper()}[/{color}]",
112
+ f.get("module", ""),
113
+ f.get("category", ""),
114
+ f.get("title", "")[:70],
115
+ str(f.get("points_deducted", 0)),
116
+ )
117
+
118
+ console.print(table)
119
+
120
+
121
+ def _render_module_breakdown(result) -> None:
122
+ if not result.module_results:
123
+ return
124
+
125
+ modules_table = Table(
126
+ title="Module Breakdown",
127
+ border_style="dim",
128
+ header_style="bold dim",
129
+ )
130
+ modules_table.add_column("Module", style="bold", width=16)
131
+ modules_table.add_column("Findings", style="white", width=10)
132
+ modules_table.add_column("Critical", style="bright_red", width=10)
133
+ modules_table.add_column("High", style="red", width=8)
134
+ modules_table.add_column("Medium", style="yellow", width=8)
135
+
136
+ for mod_id, mod_data in result.module_results.items():
137
+ findings = mod_data.get("findings", [])
138
+ crit = sum(1 for f in findings if f.get("severity") == "critical")
139
+ high = sum(1 for f in findings if f.get("severity") == "high")
140
+ med = sum(1 for f in findings if f.get("severity") == "medium")
141
+ modules_table.add_row(
142
+ mod_id.upper(),
143
+ str(len(findings)),
144
+ str(crit),
145
+ str(high),
146
+ str(med),
147
+ )
148
+
149
+ console.print(modules_table)
150
+
151
+
152
+ def _render_badge(result) -> None:
153
+ if result.badge_markdown:
154
+ console.print(Panel(
155
+ Group(
156
+ Text(" GitHub README Badge (copy-paste):", style="bold dim"),
157
+ Text(f" {result.badge_markdown}", style="cyan"),
158
+ ),
159
+ border_style="dim",
160
+ title="[dim]Badge[/dim]",
161
+ title_align="left",
162
+ padding=(0, 2),
163
+ ))
164
+
165
+
166
+ # ── CLI entry point ─────────────────────────────────────────────────────
167
+
168
+
169
+ def _add_scan_args(p: argparse.ArgumentParser) -> None:
170
+ """Add shared scan arguments to a parser."""
171
+ p.add_argument("target", help="Target domain or URL")
172
+ p.add_argument("--json", dest="json_output", action="store_true",
173
+ help="Output as JSON")
174
+ p.add_argument("-o", "--output", dest="output_file", type=str,
175
+ help="Save JSON to file")
176
+ p.add_argument("--timeout", "-t", type=int, default=8,
177
+ help="Per-request timeout in seconds (default: 8)")
178
+ p.add_argument("--insecure", "-k", action="store_true",
179
+ help="Skip TLS verification")
180
+ p.add_argument("--rate-limit", type=float, default=10.0,
181
+ help="Max requests per second (default: 10)")
182
+
183
+
184
+ def main(argv: list[str] | None = None) -> None:
185
+ parser = argparse.ArgumentParser(
186
+ prog="reconpro",
187
+ description=(
188
+ "ReconPro Enterprise — Eight Blades. One Target. One Verdict.\n"
189
+ "The full-spectrum security reconnaissance platform."
190
+ ),
191
+ epilog="Examples:\n"
192
+ " reconpro example.com\n"
193
+ " reconpro example.com --modules recon,auth,vibesec\n"
194
+ " reconpro example.com --all --json -o report.json\n"
195
+ " reconpro vibesec example.com",
196
+ formatter_class=argparse.RawDescriptionHelpFormatter,
197
+ )
198
+
199
+ parser.add_argument("--version", "-v", action="version",
200
+ version=f"ReconPro {__version__}")
201
+
202
+ subparsers = parser.add_subparsers(dest="subcommand")
203
+
204
+ # vibesec quick subcommand
205
+ vibesec_p = subparsers.add_parser("vibesec", help="Quick VibeSec benchmark")
206
+ _add_scan_args(vibesec_p)
207
+
208
+ # scan subcommand (default behavior)
209
+ scan_p = subparsers.add_parser("scan", help="Full scan with module selection")
210
+ scan_p.add_argument("target", help="Target domain or URL")
211
+ scan_p.add_argument("--modules", "-m", type=str, default=None,
212
+ help="Comma-separated module list")
213
+ scan_p.add_argument("--all", "-a", action="store_true",
214
+ help="Run all 8 modules")
215
+ scan_p.add_argument("--json", dest="json_output", action="store_true")
216
+ scan_p.add_argument("-o", "--output", dest="output_file", type=str)
217
+ scan_p.add_argument("--timeout", "-t", type=int, default=8)
218
+ scan_p.add_argument("--insecure", "-k", action="store_true")
219
+ scan_p.add_argument("--rate-limit", type=float, default=10.0)
220
+
221
+ # list subcommand
222
+ subparsers.add_parser("list", help="List available modules")
223
+
224
+ # Catchall: if first positional doesn't match a subcommand, treat as scan
225
+ args, remaining = parser.parse_known_args(argv)
226
+
227
+ # List modules
228
+ if args.subcommand == "list":
229
+ console.print("\n[bold]Available Modules:[/bold]\n")
230
+ for mid, entry in MODULE_REGISTRY.items():
231
+ default = " (default)" if mid in DEFAULT_MODULES else ""
232
+ console.print(f" [cyan]{mid:12}[/] {entry['name']:18}{default}")
233
+ console.print(f"\n [dim]Default: {', '.join(DEFAULT_MODULES)}[/]")
234
+ console.print(f" [dim]Use --all to run all 8 modules[/]\n")
235
+ return
236
+
237
+ # Handle vibesec subcommand
238
+ if args.subcommand == "vibesec":
239
+ if not args.target:
240
+ parser.parse_args(["vibesec", "--help"])
241
+ sys.exit(1)
242
+ target = args.target
243
+ modules = ["vibesec"]
244
+ json_output = args.json_output
245
+ output_file = args.output_file
246
+ timeout = args.timeout
247
+ verify_tls = not args.insecure
248
+ rate_limit = args.rate_limit
249
+ # Handle explicit scan subcommand
250
+ elif args.subcommand == "scan":
251
+ if not args.target:
252
+ parser.parse_args(["scan", "--help"])
253
+ sys.exit(1)
254
+ target = args.target
255
+ modules = ([m.strip().lower() for m in args.modules.split(",")]
256
+ if args.modules else None)
257
+ json_output = args.json_output
258
+ output_file = args.output_file
259
+ timeout = args.timeout
260
+ verify_tls = not args.insecure
261
+ rate_limit = args.rate_limit
262
+ all_modules = args.all
263
+ # Handle implicit scan (no subcommand, first arg is the target)
264
+ elif remaining and not args.subcommand:
265
+ target = remaining[0]
266
+ # Re-parse with explicit scan subcommand to get flags
267
+ scan_args = parser.parse_args(["scan"] + remaining)
268
+ modules = ([m.strip().lower() for m in scan_args.modules.split(",")]
269
+ if scan_args.modules else None)
270
+ json_output = scan_args.json_output
271
+ output_file = scan_args.output_file
272
+ timeout = scan_args.timeout
273
+ verify_tls = not scan_args.insecure
274
+ rate_limit = scan_args.rate_limit
275
+ all_modules = scan_args.all
276
+ else:
277
+ parser.print_help()
278
+ sys.exit(1)
279
+
280
+ target = target.strip()
281
+
282
+ # Banner
283
+ console.print(BANNER)
284
+ console.print(f" [dim]v{__version__} | {target} | modules: {modules or 'default'}[/]\n")
285
+ console.print(f" [bold]Scanning [cyan]{target}[/] ...[/]\n")
286
+
287
+ try:
288
+ with Progress(
289
+ SpinnerColumn(),
290
+ TextColumn("[bold]{task.description}[/]"),
291
+ TimeElapsedColumn(),
292
+ console=console,
293
+ ) as progress:
294
+ task = progress.add_task("ReconPro scanning...", total=None)
295
+ result = scan(
296
+ target,
297
+ modules=modules,
298
+ all_modules=all_modules if args.subcommand == "scan" else False,
299
+ timeout=timeout,
300
+ verify_tls=verify_tls,
301
+ rate_limit=rate_limit,
302
+ )
303
+ progress.update(task, completed=True)
304
+ except KeyboardInterrupt:
305
+ console.print("\n [yellow]Scan interrupted.[/]")
306
+ sys.exit(130)
307
+ except Exception as exc:
308
+ console.print(f" [bright_red]Error:[/] {exc}")
309
+ sys.exit(1)
310
+
311
+ # Output
312
+ if json_output:
313
+ text = json.dumps(result.to_dict(), indent=2, default=str)
314
+ if output_file:
315
+ with open(output_file, "w") as fp:
316
+ fp.write(text)
317
+ console.print(f" [green]JSON report saved to [cyan]{output_file}[/][/]")
318
+ else:
319
+ console.print(text)
320
+ else:
321
+ _render_summary(result)
322
+ console.print()
323
+ _render_module_breakdown(result)
324
+ console.print()
325
+ _render_findings_table(result)
326
+ _render_badge(result)
327
+
328
+ if output_file:
329
+ with open(output_file, "w") as fp:
330
+ fp.write(json.dumps(result.to_dict(), indent=2, default=str))
331
+ console.print(f"\n [green]JSON report saved to [cyan]{output_file}[/][/]")
332
+
333
+ console.print()
334
+ sys.exit(0)
335
+
336
+
337
+ if __name__ == "__main__":
338
+ main()