-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathquick_scan.py
More file actions
102 lines (85 loc) · 4.18 KB
/
Copy pathquick_scan.py
File metadata and controls
102 lines (85 loc) · 4.18 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
#!/usr/bin/env python3
"""
quick_scan.py
=============
Convenience CLI to scan a file or inline code snippet without bash.
Examples
--------
# Scan a file (rules-only, no model needed):
python quick_scan.py --file path/to/code.py
# Scan inline code:
python quick_scan.py --code 'cursor.execute("SELECT * FROM t WHERE id=" + uid)' --language python
# Use the trained ML model (requires models_saved/best_model.pt):
python quick_scan.py --file path/to/code.js --language javascript --use-model
"""
import argparse
import sys
from src.inference.pipeline import PolyGuardPipeline
SEVERITY_COLOR = {
"Critical": "\033[91m", # red
"High": "\033[93m", # yellow
"Medium": "\033[94m", # blue
"Low": "\033[96m", # cyan
}
RESET = "\033[0m"
BOLD = "\033[1m"
def colorize(text: str, severity: str) -> str:
return f"{SEVERITY_COLOR.get(severity, '')}{text}{RESET}"
def main():
parser = argparse.ArgumentParser(description="PolyGuard — Quick Code Scanner")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--file", help="Path to source file to scan")
group.add_argument("--code", help="Inline code snippet to scan")
parser.add_argument("--language", default="python",
choices=["python", "javascript", "cpp", "c", "typescript"],
help="Programming language (default: python)")
parser.add_argument("--use-model", action="store_true",
help="Load trained ML model (requires models_saved/best_model.pt)")
parser.add_argument("--threshold", type=float, default=0.5,
help="ML confidence threshold (default: 0.5)")
args = parser.parse_args()
# ── Load code ─────────────────────────────────────────────────────────────
if args.file:
try:
with open(args.file, "r", encoding="utf-8") as f:
code = f.read()
source_label = args.file
except FileNotFoundError:
print(f"Error: File not found: {args.file}", file=sys.stderr)
sys.exit(1)
else:
code = args.code
source_label = "<inline>"
# ── Build pipeline ────────────────────────────────────────────────────────
if args.use_model:
pipeline = PolyGuardPipeline.from_pretrained(
"models_saved/best_model.pt", threshold=args.threshold
)
else:
pipeline = PolyGuardPipeline.rules_only()
# ── Scan ──────────────────────────────────────────────────────────────────
result = pipeline.analyze(code, language=args.language)
# ── Output ────────────────────────────────────────────────────────────────
print(f"\n{BOLD}{'═'*58}{RESET}")
print(f"{BOLD} PolyGuard Security Scan{RESET}")
print(f" Source : {source_label}")
print(f" Language : {args.language}")
print(f" Risk : {colorize(result.overall_risk, result.overall_risk)}")
print(f" Time : {result.scan_time_ms:.1f} ms")
print(f"{BOLD}{'═'*58}{RESET}\n")
if not result.findings:
print(" ✅ No vulnerabilities detected.\n")
sys.exit(0)
for i, f in enumerate(result.findings, 1):
sev_str = colorize(f"[{f.severity}]", f.severity)
print(f" {BOLD}[{i}]{RESET} {sev_str} {BOLD}{f.vuln_type.upper()}{RESET}"
f" — Line {f.line} (confidence: {f.confidence:.0%}) [{f.source}]")
print(f" {f.message}")
if f.cwe:
print(f" {BOLD}CWE:{RESET} {f.cwe}")
if f.suggested_fix:
print(f" {BOLD}Fix:{RESET} {f.suggested_fix}")
print()
sys.exit(1 if result.overall_risk in ("Critical", "High") else 0)
if __name__ == "__main__":
main()