AdityaDevx commited on
Commit
65f2935
·
0 Parent(s):

fix: better 404 error

Browse files
Files changed (1) hide show
  1. api.py +117 -0
api.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel
4
+ import re, os, requests, asyncio, concurrent.futures
5
+ from dotenv import load_dotenv
6
+ from groq import Groq
7
+
8
+ load_dotenv()
9
+
10
+ app = FastAPI()
11
+ app.add_middleware(
12
+ CORSMiddleware,
13
+ allow_origins=["*"],
14
+ allow_credentials=True,
15
+ allow_methods=["*"],
16
+ allow_headers=["*"],
17
+ )
18
+
19
+ def parse_github_url(url):
20
+ m = re.match(r"https://github\.com/([^/]+)/([^/]+)/blob/[^/]+/(.+)", url.strip())
21
+ if m:
22
+ return m.group(1), m.group(2), m.group(3)
23
+ return None, None, None
24
+
25
+ def get_file_content(owner, repo, path):
26
+ token = os.getenv("GITHUB_TOKEN", "")
27
+ headers = {"Authorization": f"token {token}"} if (token and token != "your_github_personal_access_token_here") else {}
28
+ url = f"https://api.github.com/repos/{owner}/{repo}/contents/{path}"
29
+ r = requests.get(url, headers=headers, timeout=15)
30
+ if r.status_code != 200:
31
+ return None, f"GitHub API error: {r.status_code}"
32
+ import base64
33
+ data = r.json()
34
+ content = base64.b64decode(data["content"]).decode("utf-8", errors="replace")
35
+ return content, None
36
+
37
+ def run_scan(owner, repo, file_path):
38
+ code, err = get_file_content(owner, repo, file_path)
39
+ if err:
40
+ return {"error": err}
41
+
42
+ # Truncate large files
43
+ if len(code) > 8000:
44
+ code = code[:8000] + "\n... [truncated]"
45
+
46
+ client = Groq(api_key=os.getenv("GROQ_API_KEY", ""))
47
+
48
+ prompt = f"""You are a cybersecurity expert. Analyze this code for security vulnerabilities.
49
+
50
+ File: {file_path}
51
+ Repository: {owner}/{repo}
52
+
53
+ ```
54
+ {code}
55
+ ```
56
+
57
+ Provide a detailed security analysis in this exact markdown format:
58
+
59
+ # Security Analysis Report
60
+
61
+ ## File Overview
62
+ - Repository: {owner}/{repo}
63
+ - File: {file_path}
64
+ - Language: [detected language]
65
+ - Lines analyzed: [count]
66
+
67
+ ## Vulnerabilities Found
68
+
69
+ [For each vulnerability found:]
70
+ ### [Vulnerability Name] — [CRITICAL/HIGH/MEDIUM/LOW]
71
+ - **Line**: [line number or range]
72
+ - **Code**: `[vulnerable snippet]`
73
+ - **Issue**: [clear explanation]
74
+ - **CVE Reference**: [relevant CVE ID if applicable]
75
+
76
+ ## Remediation
77
+ [Specific fix for each vulnerability with corrected code]
78
+
79
+ ## Risk Summary
80
+ - Critical: [n] | High: [n] | Medium: [n] | Low: [n]
81
+ - **Overall Risk**: [CRITICAL/HIGH/MEDIUM/LOW]
82
+ """
83
+
84
+ response = client.chat.completions.create(
85
+ model="llama-3.3-70b-versatile",
86
+ messages=[{"role": "user", "content": prompt}],
87
+ temperature=0.1,
88
+ max_tokens=4096,
89
+ )
90
+ result = response.choices[0].message.content
91
+ return {"result": result}
92
+
93
+
94
+ class ScanRequest(BaseModel):
95
+ url: str
96
+
97
+
98
+ @app.post("/api/scan")
99
+ async def scan(req: ScanRequest):
100
+ owner, repo, file_path = parse_github_url(req.url)
101
+ if not owner or not repo or not file_path:
102
+ return {"error": "Invalid GitHub file URL. Must contain /blob/."}
103
+ loop = asyncio.get_event_loop()
104
+ with concurrent.futures.ThreadPoolExecutor() as pool:
105
+ result = await loop.run_in_executor(pool, run_scan, owner, repo, file_path)
106
+ return result
107
+
108
+
109
+ @app.get("/api/health")
110
+ def health():
111
+ return {"status": "ok", "groq_key_set": bool(os.getenv("GROQ_API_KEY"))}
112
+
113
+
114
+ @app.get("/")
115
+ def root():
116
+ return {"status": "Vulnerability Scanner API running"}
117
+