Add Remediate workflow type to Ivanti Queue with remediation notes
- Add 'Remediate' as a valid workflow type (vendor-required, like FP/Archer) - Create queue_remediation_notes table with FK cascade and 5000 char limit - Add POST/GET /api/ivanti/todo-queue/:id/notes endpoints - Include remediation_notes_count in queue item GET response - Add RemediationModal component for viewing/adding notes - Add notes count badge on Remediate queue items (purple #A855F7 theme) - Add delete confirmation warning when removing items with notes - Append remediation notes to Jira ticket descriptions - Add property-based tests for all correctness properties
This commit is contained in:
49
backend/migrations/add_queue_remediation_notes_table.js
Normal file
49
backend/migrations/add_queue_remediation_notes_table.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// Migration: Create queue_remediation_notes table
|
||||
// Stores remediation notes for Ivanti todo queue items (append-only).
|
||||
// FK cascade ensures notes are deleted when the parent queue item is removed.
|
||||
// Idempotent — safe to re-run multiple times.
|
||||
const pool = require('../db');
|
||||
|
||||
async function run() {
|
||||
console.log('Starting queue_remediation_notes migration...');
|
||||
|
||||
// Verify prerequisite table exists
|
||||
const { rows: queueTable } = await pool.query(`
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = 'ivanti_todo_queue'
|
||||
`);
|
||||
if (queueTable.length === 0) {
|
||||
console.error('✗ ivanti_todo_queue table does not exist. Cannot proceed.');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✓ ivanti_todo_queue table exists');
|
||||
|
||||
// Create queue_remediation_notes table
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS queue_remediation_notes (
|
||||
id SERIAL PRIMARY KEY,
|
||||
queue_item_id INTEGER NOT NULL REFERENCES ivanti_todo_queue(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL,
|
||||
username VARCHAR(100) NOT NULL,
|
||||
note_text TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
CONSTRAINT chk_note_text_length CHECK (char_length(note_text) <= 5000)
|
||||
)
|
||||
`);
|
||||
console.log('✓ queue_remediation_notes table created (or already exists)');
|
||||
|
||||
// Create index on queue_item_id for efficient lookup
|
||||
await pool.query(`
|
||||
CREATE INDEX IF NOT EXISTS idx_remediation_notes_queue_item
|
||||
ON queue_remediation_notes(queue_item_id)
|
||||
`);
|
||||
console.log('✓ queue_item_id index created (or already exists)');
|
||||
|
||||
console.log('Migration complete.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
run().catch(err => {
|
||||
console.error('Migration failed:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
48
backend/migrations/add_remediate_workflow_type.js
Normal file
48
backend/migrations/add_remediate_workflow_type.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// Migration: Add 'Remediate' to the ivanti_todo_queue workflow_type constraint
|
||||
// Uses idempotent pattern: drop constraint IF EXISTS, then re-add with full set.
|
||||
// Safe to re-run multiple times.
|
||||
const pool = require('../db');
|
||||
|
||||
async function run() {
|
||||
console.log('Starting add_remediate_workflow_type migration...');
|
||||
|
||||
// Verify prerequisite table exists
|
||||
const { rows: queueTable } = await pool.query(`
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = 'ivanti_todo_queue'
|
||||
`);
|
||||
if (queueTable.length === 0) {
|
||||
console.error('✗ ivanti_todo_queue table does not exist. Cannot proceed.');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✓ ivanti_todo_queue table exists');
|
||||
|
||||
// Drop the existing workflow_type check constraint if it exists
|
||||
await pool.query(`
|
||||
ALTER TABLE ivanti_todo_queue
|
||||
DROP CONSTRAINT IF EXISTS ivanti_todo_queue_workflow_type_check
|
||||
`);
|
||||
console.log('✓ Dropped existing workflow_type check constraint (if any)');
|
||||
|
||||
// Also drop alternative constraint name patterns
|
||||
await pool.query(`
|
||||
ALTER TABLE ivanti_todo_queue
|
||||
DROP CONSTRAINT IF EXISTS chk_workflow_type
|
||||
`);
|
||||
|
||||
// Re-add the constraint with 'Remediate' included
|
||||
await pool.query(`
|
||||
ALTER TABLE ivanti_todo_queue
|
||||
ADD CONSTRAINT ivanti_todo_queue_workflow_type_check
|
||||
CHECK (workflow_type IN ('FP', 'Archer', 'CARD', 'GRANITE', 'DECOM', 'Remediate'))
|
||||
`);
|
||||
console.log('✓ Added workflow_type check constraint with Remediate included');
|
||||
|
||||
console.log('Migration complete.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
run().catch(err => {
|
||||
console.error('Migration failed:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -27,6 +27,8 @@ const POSTGRES_MIGRATIONS = [
|
||||
'drop_jira_status_check_constraint.js',
|
||||
'add_compliance_history_metric_id.js',
|
||||
'add_archer_templates_table.js',
|
||||
'add_queue_remediation_notes_table.js',
|
||||
'add_remediate_workflow_type.js',
|
||||
];
|
||||
|
||||
async function runAll() {
|
||||
|
||||
Reference in New Issue
Block a user