Add weekly vulnerability report upload feature

Implements a comprehensive system for uploading and processing weekly
vulnerability reports that automatically splits multiple CVE IDs in a
single cell into separate rows for easier filtering and analysis.

Backend Changes:
- Add weekly_reports table with migration
- Create Excel processor helper using Python child_process
- Implement API routes for upload, list, download, delete
- Mount routes in server.js after multer initialization
- Move split_cve_report.py to backend/scripts/

Frontend Changes:
- Add WeeklyReportModal component with phase-based UI
- Add "Weekly Report" button next to NVD Sync
- Integrate modal into App.js with state management
- Display existing reports with current report indicator
- Download buttons for original and processed files

Features:
- Upload .xlsx files (editor/admin only)
- Automatic CVE ID splitting via Python script
- Store metadata in database + files on filesystem
- Auto-archive previous reports (mark one as current)
- Download both original and processed versions
- Audit logging for all operations
- Security: file validation, auth checks, path sanitization

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 16:41:39 -07:00
parent bf3d01becf
commit 0d67a99c7e
9 changed files with 1020 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ import UserMenu from './components/UserMenu';
import UserManagement from './components/UserManagement';
import AuditLog from './components/AuditLog';
import NvdSyncModal from './components/NvdSyncModal';
import WeeklyReportModal from './components/WeeklyReportModal';
import './App.css';
const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api';
@@ -173,6 +174,7 @@ export default function App() {
const [showUserManagement, setShowUserManagement] = useState(false);
const [showAuditLog, setShowAuditLog] = useState(false);
const [showNvdSync, setShowNvdSync] = useState(false);
const [showWeeklyReport, setShowWeeklyReport] = useState(false);
const [newCVE, setNewCVE] = useState({
cve_id: '',
vendor: '',
@@ -757,6 +759,15 @@ export default function App() {
NVD Sync
</button>
)}
{canWrite() && (
<button
onClick={() => setShowWeeklyReport(true)}
className="intel-button intel-button-success relative z-10 flex items-center gap-2"
>
<Upload className="w-4 h-4" />
Weekly Report
</button>
)}
{canWrite() && (
<button
onClick={() => setShowAddCVE(true)}
@@ -810,6 +821,11 @@ export default function App() {
<NvdSyncModal onClose={() => setShowNvdSync(false)} onSyncComplete={() => fetchCVEs()} />
)}
{/* Weekly Report Modal */}
{showWeeklyReport && (
<WeeklyReportModal onClose={() => setShowWeeklyReport(false)} />
)}
{/* Add CVE Modal */}
{showAddCVE && (
<div className="fixed inset-0 modal-overlay flex items-center justify-center z-50 p-4">