-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
192 lines (150 loc) · 6.14 KB
/
Copy pathapp.py
File metadata and controls
192 lines (150 loc) · 6.14 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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
"""
app.py
------
Flask entry point for the Vulnerability Management dashboard.
Defines all REST API routes and serves the single-page frontend.
"""
from flask import Flask, request, jsonify, render_template
from database import init_db, get_db
app = Flask(__name__)
# ---------------------------------------------------------------------------
# Serve the dashboard SPA
# ---------------------------------------------------------------------------
@app.route("/")
def index():
"""Render the main dashboard HTML page."""
return render_template("index.html")
# ---------------------------------------------------------------------------
# Stats endpoint – used to populate KPI cards
# ---------------------------------------------------------------------------
@app.route("/api/stats")
def get_stats():
"""Return vulnerability counts grouped by severity and overall totals."""
conn = get_db()
cursor = conn.cursor()
# Total count
total = cursor.execute("SELECT COUNT(*) FROM vulnerabilities").fetchone()[0]
# Count per severity
severity_rows = cursor.execute(
"SELECT severity, COUNT(*) as cnt FROM vulnerabilities GROUP BY severity"
).fetchall()
# Count per status
status_rows = cursor.execute(
"SELECT status, COUNT(*) as cnt FROM vulnerabilities GROUP BY status"
).fetchall()
conn.close()
severity_counts = {row["severity"]: row["cnt"] for row in severity_rows}
status_counts = {row["status"]: row["cnt"] for row in status_rows}
return jsonify({
"total": total,
"critical": severity_counts.get("Critical", 0),
"high": severity_counts.get("High", 0),
"medium": severity_counts.get("Medium", 0),
"low": severity_counts.get("Low", 0),
"open": status_counts.get("Open", 0),
"in_progress": status_counts.get("In Progress", 0),
"resolved": status_counts.get("Resolved", 0),
})
# ---------------------------------------------------------------------------
# Vulnerabilities – CRUD routes
# ---------------------------------------------------------------------------
@app.route("/api/vulnerabilities", methods=["GET"])
def list_vulnerabilities():
"""
Return all vulnerabilities, optionally filtered by severity or status.
Query params: ?severity=Critical&status=Open
"""
conn = get_db()
cursor = conn.cursor()
query = "SELECT * FROM vulnerabilities WHERE 1=1"
params = []
severity = request.args.get("severity")
if severity:
query += " AND severity = ?"
params.append(severity)
status = request.args.get("status")
if status:
query += " AND status = ?"
params.append(status)
query += " ORDER BY CASE severity WHEN 'Critical' THEN 1 WHEN 'High' THEN 2 WHEN 'Medium' THEN 3 WHEN 'Low' THEN 4 END, id DESC"
rows = cursor.execute(query, params).fetchall()
conn.close()
return jsonify([dict(row) for row in rows])
@app.route("/api/vulnerabilities", methods=["POST"])
def create_vulnerability():
"""Create a new vulnerability record from JSON body."""
data = request.get_json()
if not data:
return jsonify({"error": "No data provided"}), 400
required = ["title", "severity"]
missing = [f for f in required if not data.get(f)]
if missing:
return jsonify({"error": f"Missing required fields: {', '.join(missing)}"}), 400
conn = get_db()
cursor = conn.cursor()
cursor.execute("""
INSERT INTO vulnerabilities (title, description, severity, status, affected_asset, discovered_date)
VALUES (?, ?, ?, ?, ?, ?)
""", (
data.get("title"),
data.get("description", ""),
data.get("severity"),
data.get("status", "Open"),
data.get("affected_asset", ""),
data.get("discovered_date", ""),
))
conn.commit()
new_id = cursor.lastrowid
new_row = cursor.execute("SELECT * FROM vulnerabilities WHERE id = ?", (new_id,)).fetchone()
conn.close()
return jsonify(dict(new_row)), 201
@app.route("/api/vulnerabilities/<int:vuln_id>", methods=["PUT"])
def update_vulnerability(vuln_id):
"""Update an existing vulnerability by ID."""
data = request.get_json()
if not data:
return jsonify({"error": "No data provided"}), 400
conn = get_db()
cursor = conn.cursor()
# Verify it exists
existing = cursor.execute("SELECT * FROM vulnerabilities WHERE id = ?", (vuln_id,)).fetchone()
if not existing:
conn.close()
return jsonify({"error": "Vulnerability not found"}), 404
cursor.execute("""
UPDATE vulnerabilities
SET title = ?, description = ?, severity = ?, status = ?, affected_asset = ?, discovered_date = ?
WHERE id = ?
""", (
data.get("title", existing["title"]),
data.get("description", existing["description"]),
data.get("severity", existing["severity"]),
data.get("status", existing["status"]),
data.get("affected_asset", existing["affected_asset"]),
data.get("discovered_date",existing["discovered_date"]),
vuln_id,
))
conn.commit()
updated = cursor.execute("SELECT * FROM vulnerabilities WHERE id = ?", (vuln_id,)).fetchone()
conn.close()
return jsonify(dict(updated))
@app.route("/api/vulnerabilities/<int:vuln_id>", methods=["DELETE"])
def delete_vulnerability(vuln_id):
"""Delete a vulnerability by ID."""
conn = get_db()
cursor = conn.cursor()
existing = cursor.execute("SELECT id FROM vulnerabilities WHERE id = ?", (vuln_id,)).fetchone()
if not existing:
conn.close()
return jsonify({"error": "Vulnerability not found"}), 404
cursor.execute("DELETE FROM vulnerabilities WHERE id = ?", (vuln_id,))
conn.commit()
conn.close()
return jsonify({"message": "Vulnerability deleted successfully"}), 200
# ---------------------------------------------------------------------------
# App entry point
# ---------------------------------------------------------------------------
if __name__ == "__main__":
# Initialize the database (creates tables and seeds data if needed)
init_db()
app.run(debug=True, port=5000)