Add flexible Jira ticket creation — CVE/Vendor optional, source context tracking

Make CVE ID and Vendor optional when creating Jira tickets. Add source_context
field to track ticket origin (cve, archer, ivanti_queue, email, manual).

- Migration: drop NOT NULL on cve_id/vendor, add source_context column with CHECK
- Backend: update create/update/get endpoints for optional fields and source_context
- Frontend: update creation modal with optional labels and source context dropdown
- Add Create Jira Ticket action from Ivanti queue (pre-populates from finding)
- Add Create Jira Ticket action from Archer detail view (pre-populates from ticket)
- Add source context badge column, filter dropdown, and search to ticket list
This commit is contained in:
Jordan Ramos
2026-05-21 15:06:16 -06:00
parent 940cb3251c
commit dff1fa3cc9
7 changed files with 1117 additions and 94 deletions

View File

@@ -0,0 +1,73 @@
// Migration: Add flexible Jira ticket creation support
// - Drops NOT NULL on cve_id and vendor columns
// - Adds source_context column with CHECK constraint
// - Backfills existing rows with source_context = 'manual'
// - Adds index on source_context
// Idempotent — safe to run multiple times.
const pool = require('../db');
async function run() {
console.log('Starting flexible Jira ticket creation migration...');
// Verify jira_tickets table exists before proceeding
const { rows } = await pool.query(`
SELECT 1 FROM information_schema.tables
WHERE table_schema = 'public' AND table_name = 'jira_tickets'
`);
if (rows.length === 0) {
console.error('✗ jira_tickets table does not exist. Cannot proceed.');
process.exit(1);
}
console.log('✓ jira_tickets table exists');
// Drop NOT NULL constraint on cve_id (idempotent — no-op if already nullable)
await pool.query(`ALTER TABLE jira_tickets ALTER COLUMN cve_id DROP NOT NULL`);
console.log('✓ cve_id NOT NULL constraint dropped (or was already nullable)');
// Drop NOT NULL constraint on vendor (idempotent — no-op if already nullable)
await pool.query(`ALTER TABLE jira_tickets ALTER COLUMN vendor DROP NOT NULL`);
console.log('✓ vendor NOT NULL constraint dropped (or was already nullable)');
// Add source_context column with default value (IF NOT EXISTS makes it idempotent)
await pool.query(`
ALTER TABLE jira_tickets
ADD COLUMN IF NOT EXISTS source_context TEXT DEFAULT 'manual'
`);
console.log('✓ source_context column added (or already exists)');
// Add CHECK constraint for allowed source_context values (idempotent guard)
await pool.query(`
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'jira_tickets_source_context_check'
) THEN
ALTER TABLE jira_tickets
ADD CONSTRAINT jira_tickets_source_context_check
CHECK (source_context IN ('cve', 'archer', 'ivanti_queue', 'email', 'manual'));
END IF;
END $$;
`);
console.log('✓ source_context CHECK constraint added (or already exists)');
// Backfill existing rows where source_context is NULL
const result = await pool.query(`
UPDATE jira_tickets SET source_context = 'manual' WHERE source_context IS NULL
`);
console.log(`✓ Backfilled ${result.rowCount} rows with source_context = 'manual'`);
// Add index on source_context for filtering performance
await pool.query(`
CREATE INDEX IF NOT EXISTS idx_jira_tickets_source_context
ON jira_tickets(source_context)
`);
console.log('✓ source_context index created (or already exists)');
console.log('Migration complete.');
process.exit(0);
}
run().catch(err => {
console.error('Migration failed:', err.message);
process.exit(1);
});