Files
cve-dashboard/backend/migrations/add_sync_anomaly_tables.js

91 lines
3.3 KiB
JavaScript
Raw Normal View History

// Migration: Add sync anomaly detection and BU drift monitoring tables
//
// Creates two new tables:
// - ivanti_sync_anomaly_log — stores one row per sync cycle with the
// anomaly summary breakdown (count deltas, classification, significance).
// - ivanti_finding_bu_history — records BU change events detected on
// individual findings across syncs.
//
// Safe to re-run — uses CREATE TABLE IF NOT EXISTS and CREATE INDEX IF NOT EXISTS.
//
// Usage: node backend/migrations/add_sync_anomaly_tables.js
const path = require('path');
const sqlite3 = require('sqlite3').verbose();
const dbPath = path.join(__dirname, '..', 'cve_database.db');
const db = new sqlite3.Database(dbPath);
console.log('Starting sync anomaly tables migration...');
function run(sql, params = []) {
return new Promise((resolve, reject) => {
db.run(sql, params, function (err) {
if (err) reject(err);
else resolve(this);
});
});
}
function all(sql, params = []) {
return new Promise((resolve, reject) => {
db.all(sql, params, (err, rows) => {
if (err) reject(err);
else resolve(rows || []);
});
});
}
async function migrate() {
// 1. Create ivanti_sync_anomaly_log table
await run(`
CREATE TABLE IF NOT EXISTS ivanti_sync_anomaly_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sync_timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
open_count_delta INTEGER NOT NULL DEFAULT 0,
closed_count_delta INTEGER NOT NULL DEFAULT 0,
newly_archived_count INTEGER NOT NULL DEFAULT 0,
returned_count INTEGER NOT NULL DEFAULT 0,
classification_json TEXT NOT NULL DEFAULT '{}',
is_significant INTEGER NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✓ ivanti_sync_anomaly_log table ready');
// 2. Create ivanti_finding_bu_history table
await run(`
CREATE TABLE IF NOT EXISTS ivanti_finding_bu_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
finding_id TEXT NOT NULL,
finding_title TEXT NOT NULL DEFAULT '',
host_name TEXT NOT NULL DEFAULT '',
previous_bu TEXT NOT NULL,
new_bu TEXT NOT NULL,
detected_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✓ ivanti_finding_bu_history table ready');
// 3. Create indexes
await run('CREATE INDEX IF NOT EXISTS idx_anomaly_sync_timestamp ON ivanti_sync_anomaly_log(sync_timestamp)');
console.log('✓ idx_anomaly_sync_timestamp index ready');
await run('CREATE INDEX IF NOT EXISTS idx_bu_history_finding_id ON ivanti_finding_bu_history(finding_id)');
console.log('✓ idx_bu_history_finding_id index ready');
await run('CREATE INDEX IF NOT EXISTS idx_bu_history_detected_at ON ivanti_finding_bu_history(detected_at)');
console.log('✓ idx_bu_history_detected_at index ready');
}
migrate()
.then(() => {
console.log('Migration complete.');
db.close();
})
.catch((err) => {
console.error('Migration failed:', err);
db.close();
process.exit(1);
});