Files
cve-dashboard/.kiro/specs/ivanti-fp-workflow-submission/tasks.md
jramos 382bc81a7e feat: add Ivanti FP workflow submission from Queue
- Add shared ivantiApi.js helper (ivantiPost + ivantiMultipartPost)
- Add ivantiFpWorkflow.js backend route with validation, Ivanti API
  workflow creation, attachment uploads, submission tracking, and audit
- Add add_fp_submissions_table.js migration
- Wire route into server.js at /api/ivanti/fp-workflow
- Add FpWorkflowModal component in ReportingPage.js with form fields,
  drag-and-drop file upload, progress indicator, and result views
- Add Create FP Workflow button to QueuePanel footer (editor/admin only)
- Refactor ivantiWorkflows.js and ivantiFindings.js to use shared helper
2026-04-07 16:20:24 -06:00

8.8 KiB

Implementation Plan: Ivanti FP Workflow Submission

Overview

Implement the ability to select FP-type items from the Ivanti Queue and submit False Positive workflows to the Ivanti/RiskSense API, with file attachment support, local submission tracking, and audit logging. The implementation follows existing codebase conventions: factory-pattern Express routes, Multer for file uploads, inline React component styles with the dark tactical theme, and the ivantiPost() HTTP helper for Ivanti API calls.

Tasks

  • 1. Database migration and shared helpers

    • 1.1 Create migration script backend/migrations/add_fp_submissions_table.js

      • Create ivanti_fp_submissions table with columns: id, user_id, username, ivanti_workflow_batch_id, ivanti_generated_id, workflow_name, reason, description, expiration_date, scope_override, finding_ids_json, queue_item_ids_json, attachment_count, attachment_results_json, status (success/partial/failed), error_message, created_at
      • Add indexes on user_id and ivanti_generated_id
      • Follow existing migration pattern from add_ivanti_todo_queue_table.js
      • Requirements: 6.1
    • 1.2 Extract shared Ivanti API helpers into backend/helpers/ivantiApi.js

      • Move the ivantiPost() function from ivantiWorkflows.js into a shared module
      • Add ivantiMultipartPost(urlPath, fileBuffer, fileName, apiKey, skipTls) for attachment uploads using Node.js https module with multipart/form-data boundary construction
      • Export both functions; update ivantiWorkflows.js and ivantiFindings.js to import from the shared module
      • Requirements: 4.1, 4.2
  • 2. Backend route — validation and payload construction

    • 2.1 Create backend/routes/ivantiFpWorkflow.js with validation and payload builder

      • Export createIvantiFpWorkflowRouter(db, requireAuth) factory function
      • Implement POST / route with requireAuth(db) and requireGroup('Admin', 'Standard_User') middleware
      • Configure Multer for up to 10 file uploads, 10MB each, with allowed extensions: .pdf, .png, .jpg, .jpeg, .gif, .doc, .docx, .xlsx, .csv, .txt, .zip
      • Implement validateFpWorkflowForm(body) — returns error map for invalid fields (name required max 255, reason required, description max 2000, expirationDate required and must be future date)
      • Implement buildIvantiPayload(formData, findingIds) — constructs the Ivanti API request body with type "FALSE_POSITIVE", scopeOverrideAuthorization mapping, and hostFindingIds as integers
      • Implement isAllowedFileExtension(filename) — checks against the allowed extensions list (case-insensitive)
      • Verify all queueItemIds belong to the requesting user, are FP-type, and have pending status
      • Requirements: 2.4, 2.5, 3.3, 3.4, 3.5, 4.1, 7.1
    • * 2.2 Write property tests for validation and payload construction

      • Property 3: Form Validation Correctness — For any form state, validation passes iff all required fields present and expiration date is future; error map keys match invalid fields only
      • Property 4: File Extension Validation — For any filename, acceptance returns true iff extension is in the allowed set (case-insensitive)
      • Property 5: API Payload Construction — For any valid form input, the constructed payload contains correct type, name, reason, expirationDate, scopeOverrideAuthorization, and hostFindingIds as integers
      • Use fast-check library with minimum 100 iterations per property
      • Validates: Requirements 2.4, 2.5, 3.3, 4.1
  • 3. Backend route — Ivanti API submission and local persistence

    • 3.1 Implement the submission flow in ivantiFpWorkflow.js

      • Call Ivanti API POST /client/{clientId}/workflowBatch to create the FP workflow batch
      • If attachments present, upload each via ivantiMultipartPost() to /client/{clientId}/workflowBatch/{id}/attachment
      • Handle Ivanti API error responses: 401 (invalid key), 419 (insufficient privileges), 429 (rate limited), other errors
      • On success: insert submission record into ivanti_fp_submissions, call logAudit() with action "ivanti_fp_workflow_created"
      • On failure: call logAudit() with action "ivanti_fp_workflow_failed"
      • Mark associated queue items as complete via UPDATE ivanti_todo_queue SET status='complete'
      • Handle partial failures (workflow created but attachment upload failed) — save with status "partial"
      • Return structured response with workflowBatchId, generatedId, attachmentResults, queueItemsUpdated
      • Requirements: 4.1, 4.2, 4.5, 4.6, 4.7, 4.8, 5.1, 6.1, 6.2, 6.3
    • * 3.2 Write property tests for queue item completion and submission persistence

      • Property 6: Queue Items Marked Complete on Success — For any set of queue item IDs after successful submission, all items have status "complete"
      • Property 7: Post-Submission Persistence Completeness — For any successful submission, the record contains all required fields (ivanti_workflow_batch_id, workflow_name, user_id, finding_ids_json, created_at) and audit entry has correct action/entity_type/details
      • Use in-memory SQLite for test isolation
      • Validates: Requirements 5.1, 6.1, 6.2
  • 4. Wire backend route into server.js

    • 4.1 Register the new route in backend/server.js
      • Add const createIvantiFpWorkflowRouter = require('./routes/ivantiFpWorkflow');
      • Mount at app.use('/api/ivanti/fp-workflow', createIvantiFpWorkflowRouter(db, requireAuth));
      • Place near the existing Ivanti route registrations
      • Requirements: 7.1
  • 5. Checkpoint — Backend complete

    • Ensure all tests pass, ask the user if questions arise.
  • 6. Frontend — FP Workflow Modal component

    • 6.1 Implement FpWorkflowModal in frontend/src/components/pages/ReportingPage.js

      • Add the modal component inline in ReportingPage.js following the existing pattern (QueuePanel, AddToQueuePopover are in the same file)
      • Props: open, onClose, selectedItems (FP queue items), onSuccess
      • Form fields: workflow name (text input, required), reason (textarea, required), description (textarea, optional), expiration date (date input, required), scope override toggle (Authorized/None, default Authorized)
      • Display selected findings summary: finding_id, finding_title, CVEs for each item
      • File upload area: drag-and-drop zone, file list with name/size/remove button, validate extensions and 10MB limit client-side
      • Submit button with progress indicator (creating workflow → uploading attachment N of M)
      • Error display: inline validation errors, API error messages with form state preservation
      • Success display: workflow batch ID (e.g., "FP#12345") with close/done action
      • Style with inline style objects matching the dark tactical theme from DESIGN_SYSTEM.md
      • Icons from lucide-react (Upload, FileText, X, Check, AlertTriangle, Loader)
      • Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 3.1, 3.2, 3.3, 3.4, 3.5, 4.3, 4.4, 4.7, 4.8
    • * 6.2 Write property tests for frontend validation helpers

      • Property 1: FP Workflow Button Enabled State — For any set of queue items and selection, button enabled iff selection contains at least one pending FP item
      • Property 2: FP-Only Item Filtering — For any mixed-type selection, filtered result contains only FP items
      • Property 8: Role-Based UI Visibility — For any user role, button visible iff role is editor or admin
      • Extract isCreateFpButtonEnabled, filterFpItems, shouldShowFpButton as testable pure functions
      • Use fast-check with minimum 100 iterations
      • Validates: Requirements 1.1, 1.2, 7.2
  • 7. Frontend — QueuePanel integration

    • 7.1 Add "Create FP Workflow" button and modal wiring in QueuePanel
      • Add "Create FP Workflow" button in QueuePanel footer, styled with amber/FP accent color
      • Button enabled only when selectedIds contains at least one pending FP-type item
      • Disabled state shows tooltip: "Select pending FP items to create a workflow"
      • Hide button entirely for viewer role users (check via useAuth context)
      • On click: filter selected items to FP-only, open FpWorkflowModal with filtered items
      • Wire onSuccess callback to trigger queue refresh (call existing fetch function from parent)
      • Requirements: 1.1, 1.2, 1.3, 1.4, 5.2, 7.2, 7.3
  • 8. Final checkpoint — Full integration

    • Ensure all tests pass, ask the user if questions arise.

Notes

  • Tasks marked with * are optional and can be skipped for faster MVP
  • Each task references specific requirements for traceability
  • Property tests use fast-check library — install via npm install --save-dev fast-check in both backend and frontend
  • The shared Ivanti API helper (task 1.2) updates existing imports in ivantiWorkflows.js and ivantiFindings.js — test those routes still work after the refactor
  • Multer is already a project dependency (used for document uploads in server.js)