Updated fetchcve scripts with enrichments.
This commit is contained in:
169
scripts/analyzeDatabaseQuality.js
Normal file
169
scripts/analyzeDatabaseQuality.js
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import mysql from 'mysql2/promise';
|
||||
|
||||
function log(msg) {
|
||||
const now = new Date().toLocaleString('en-AU', {
|
||||
day: '2-digit', month: 'short', year: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true
|
||||
}).replace(/\b(AM|PM)\b/, m => m.toLowerCase());
|
||||
console.log(`[${now}] ${msg}`);
|
||||
}
|
||||
|
||||
async function analyzeDatabaseQuality() {
|
||||
const db = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
});
|
||||
|
||||
log('🔍 Analyzing CVE Database Quality...\n');
|
||||
log('━'.repeat(70));
|
||||
|
||||
// Total CVEs
|
||||
const [total] = await db.query('SELECT COUNT(*) as count FROM cves');
|
||||
log(`📊 Total CVEs: ${total[0].count.toLocaleString()}`);
|
||||
|
||||
// CVEs with CVSS v3 scores
|
||||
const [v3] = await db.query('SELECT COUNT(*) as count FROM cves WHERE cvss_score_v3 IS NOT NULL');
|
||||
const v3Pct = ((v3[0].count / total[0].count) * 100).toFixed(1);
|
||||
log(`📈 CVEs with CVSS v3 scores: ${v3[0].count.toLocaleString()} (${v3Pct}%)`);
|
||||
|
||||
// CVEs with CVSS v2 scores
|
||||
const [v2] = await db.query('SELECT COUNT(*) as count FROM cves WHERE cvss_score_v2 IS NOT NULL');
|
||||
const v2Pct = ((v2[0].count / total[0].count) * 100).toFixed(1);
|
||||
log(`📈 CVEs with CVSS v2 scores: ${v2[0].count.toLocaleString()} (${v2Pct}%)`);
|
||||
|
||||
// CVEs with CVSS v4 scores
|
||||
const [v4] = await db.query('SELECT COUNT(*) as count FROM cves WHERE cvss_score_v4 IS NOT NULL');
|
||||
const v4Pct = ((v4[0].count / total[0].count) * 100).toFixed(1);
|
||||
log(`📈 CVEs with CVSS v4 scores: ${v4[0].count.toLocaleString()} (${v4Pct}%)`);
|
||||
|
||||
// CVEs with CWE IDs
|
||||
const [cwe] = await db.query('SELECT COUNT(*) as count FROM cves WHERE cwe_ids IS NOT NULL AND cwe_ids != ""');
|
||||
const cwePct = ((cwe[0].count / total[0].count) * 100).toFixed(1);
|
||||
log(`🏷️ CVEs with CWE IDs: ${cwe[0].count.toLocaleString()} (${cwePct}%)`);
|
||||
|
||||
// CVEs with references
|
||||
const [refs] = await db.query('SELECT COUNT(*) as count FROM cves WHERE `references` IS NOT NULL AND `references` != ""');
|
||||
const refsPct = ((refs[0].count / total[0].count) * 100).toFixed(1);
|
||||
log(`🔗 CVEs with references: ${refs[0].count.toLocaleString()} (${refsPct}%)`);
|
||||
|
||||
// KEV data
|
||||
const [kev] = await db.query('SELECT COUNT(*) as count FROM kev_catalog');
|
||||
log(`🛡️ Known Exploited Vulnerabilities (KEV): ${kev[0].count.toLocaleString()}`);
|
||||
|
||||
// Microsoft CVEs
|
||||
const [msrc] = await db.query('SELECT COUNT(*) as count FROM microsoft_cves');
|
||||
log(`🖥️ Microsoft CVEs: ${msrc[0].count.toLocaleString()}`);
|
||||
|
||||
// CPE matches
|
||||
const [cpe] = await db.query('SELECT COUNT(*) as count FROM cpe_matches');
|
||||
log(`💿 CPE matches (affected software): ${cpe[0].count.toLocaleString()}`);
|
||||
|
||||
log('\n━'.repeat(70));
|
||||
log('📅 CVEs by Severity (CVSS v3):');
|
||||
log('━'.repeat(70));
|
||||
|
||||
const [severity] = await db.query(`
|
||||
SELECT
|
||||
severity_v3,
|
||||
COUNT(*) as count,
|
||||
ROUND(AVG(cvss_score_v3), 1) as avg_score
|
||||
FROM cves
|
||||
WHERE severity_v3 IS NOT NULL
|
||||
GROUP BY severity_v3
|
||||
ORDER BY
|
||||
CASE severity_v3
|
||||
WHEN 'CRITICAL' THEN 1
|
||||
WHEN 'HIGH' THEN 2
|
||||
WHEN 'MEDIUM' THEN 3
|
||||
WHEN 'LOW' THEN 4
|
||||
ELSE 5
|
||||
END
|
||||
`);
|
||||
|
||||
severity.forEach(row => {
|
||||
const pct = ((row.count / total[0].count) * 100).toFixed(1);
|
||||
const icon = {
|
||||
'CRITICAL': '🔴',
|
||||
'HIGH': '🟠',
|
||||
'MEDIUM': '🟡',
|
||||
'LOW': '🟢'
|
||||
}[row.severity_v3] || '⚪';
|
||||
log(`${icon} ${(row.severity_v3 || 'UNKNOWN').padEnd(10)} ${row.count.toString().padStart(8)} (${pct.padStart(5)}%) - Avg: ${row.avg_score}`);
|
||||
});
|
||||
|
||||
log('\n━'.repeat(70));
|
||||
log('📅 Recent Activity (Last 30 Days):');
|
||||
log('━'.repeat(70));
|
||||
|
||||
const [recent] = await db.query(`
|
||||
SELECT COUNT(*) as count
|
||||
FROM cves
|
||||
WHERE last_modified_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)
|
||||
`);
|
||||
log(`🆕 CVEs modified in last 30 days: ${recent[0].count.toLocaleString()}`);
|
||||
|
||||
const [recentPub] = await db.query(`
|
||||
SELECT COUNT(*) as count
|
||||
FROM cves
|
||||
WHERE published_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)
|
||||
`);
|
||||
log(`📝 CVEs published in last 30 days: ${recentPub[0].count.toLocaleString()}`);
|
||||
|
||||
log('\n━'.repeat(70));
|
||||
log('🎯 Data Quality Score:');
|
||||
log('━'.repeat(70));
|
||||
|
||||
const qualityScore = (
|
||||
(parseFloat(v3Pct) * 0.3) + // 30% weight on CVSS v3
|
||||
(parseFloat(cwePct) * 0.2) + // 20% weight on CWE
|
||||
(parseFloat(refsPct) * 0.2) + // 20% weight on references
|
||||
((cpe[0].count > 0 ? 100 : 0) * 0.15) + // 15% weight on CPE existence
|
||||
((kev[0].count > 0 ? 100 : 0) * 0.15) // 15% weight on KEV data
|
||||
);
|
||||
|
||||
log(`Overall Quality: ${qualityScore.toFixed(1)}%`);
|
||||
|
||||
if (qualityScore >= 90) log('✅ Excellent - Highly enriched database');
|
||||
else if (qualityScore >= 75) log('✅ Good - Well enriched database');
|
||||
else if (qualityScore >= 60) log('⚠️ Fair - Some enrichment needed');
|
||||
else log('❌ Poor - Significant enrichment needed');
|
||||
|
||||
log('\n━'.repeat(70));
|
||||
log('💡 Recommendations:');
|
||||
log('━'.repeat(70));
|
||||
|
||||
if (parseFloat(v3Pct) < 80) {
|
||||
log('⚠️ Run CVE enrichment to get more CVSS v3 scores');
|
||||
log(' Use: POST /api/admin/scripts/fetch-cve (runs fetchCVE_v2.js in enrichment mode)');
|
||||
}
|
||||
|
||||
if (parseFloat(cwePct) < 70) {
|
||||
log('⚠️ Low CWE coverage - consider running enrichment');
|
||||
}
|
||||
|
||||
if (kev[0].count < 1000) {
|
||||
log('⚠️ KEV data seems low - run: POST /api/admin/scripts/fetch-kev');
|
||||
}
|
||||
|
||||
if (msrc[0].count < 10000) {
|
||||
log('⚠️ Microsoft CVE data seems low - run: POST /api/admin/scripts/fetch-msrc');
|
||||
}
|
||||
|
||||
if (recent[0].count < 100) {
|
||||
log('⚠️ No recent updates detected - run daily sync to stay current');
|
||||
log(' Use: POST /api/admin/scripts/fetch-cve');
|
||||
}
|
||||
|
||||
await db.end();
|
||||
log('\n✅ Analysis complete!\n');
|
||||
}
|
||||
|
||||
analyzeDatabaseQuality().catch(err => {
|
||||
console.error('❌ Error:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user