Files
cve-dashboard/.kiro/specs/fp-submissions-cleanup/tasks.md

3.8 KiB

Tasks

Task 1: Database Migration — Add dismissed_at Column

  • 1.1 Create migration file backend/migrations/add_fp_submissions_dismissed.js that adds a dismissed_at TIMESTAMPTZ DEFAULT NULL column to the ivanti_fp_submissions table using ALTER TABLE ... ADD COLUMN IF NOT EXISTS
  • 1.2 Run the migration and verify the column exists in the database schema

Task 2: Backend — Dismiss Endpoint

  • 2.1 Add PATCH /submissions/:id/dismiss endpoint to backend/routes/ivantiFpWorkflow.js with requireAuth() and requireGroup('Admin', 'Standard_User') middleware
  • 2.2 Implement ownership verification (user_id match, return 403 if mismatch)
  • 2.3 Implement lifecycle guard (only lifecycle_status === 'rejected' can be dismissed, return 400 otherwise)
  • 2.4 Set dismissed_at = NOW() on the submission record on success
  • 2.5 Log audit entry with action ivanti_fp_submission_dismissed, entity_type ivanti_workflow, and the workflow batch ID as entity_id

Task 3: Backend — Pure Filter Function

  • 3.1 Create and export filterVisibleSubmissions(submissions) function in backend/routes/ivantiFpWorkflow.js that excludes submissions with lifecycle_status === 'approved' or dismissed_at !== null
  • 3.2 Create and export shouldShowDismissButton(submission) predicate that returns true only when lifecycle_status === 'rejected' and dismissed_at is null

Task 4: Frontend — Filter Approved and Dismissed Submissions

  • 4.1 Modify the fpSubmissions useMemo in ReportingPage.js to filter out submissions where lifecycle_status === 'approved' or dismissed_at is not null before passing to the QueuePanel
  • 4.2 Verify that the FpEditModal can still be opened for approved submissions from Reporting Table workflow badges (no filtering on that path)

Task 5: Frontend — Dismiss Button on Rejected Submissions

  • 5.1 Add an X button (lucide X icon, 12px) to the right side of submission rows where lifecycle_status === 'rejected' in the QueuePanel submissions section
  • 5.2 Implement click handler that calls PATCH /api/ivanti/fp-workflow/submissions/:id/dismiss and removes the submission from the visible list on success
  • 5.3 Use e.stopPropagation() on the X button to prevent triggering the row's click-to-edit handler
  • 5.4 Show error feedback if the dismiss API call fails

Task 6: Frontend — Collapsible Submissions Section

  • 6.1 Add submissionsCollapsed state initialized from localStorage.getItem('steam_submissions_collapsed'), defaulting to false (expanded)
  • 6.2 Add a clickable chevron icon (ChevronDown when expanded, ChevronUp when collapsed) to the SUBMISSIONS header row
  • 6.3 Conditionally render the submissions list based on collapsed state — when collapsed, hide the list but keep the header with the count badge visible
  • 6.4 Persist collapsed/expanded state to localStorage on toggle using key steam_submissions_collapsed

Task 7: Property-Based Tests

  • 7.1 Create backend/__tests__/fp-submissions-cleanup.property.test.js with fast-check
  • 7.2 Implement Property 1 test: for any array of submissions with random lifecycle_status and dismissed_at values, filterVisibleSubmissions returns only non-approved and non-dismissed submissions (min 100 iterations)
  • 7.3 Implement Property 2 test: for any submission with random lifecycle_status and dismissed_at, shouldShowDismissButton returns true iff status is 'rejected' and dismissed_at is null (min 100 iterations)

Task 8: Unit and Integration Tests

  • 8.1 Write unit tests for the dismiss endpoint (happy path, wrong status, ownership check, not found)
  • 8.2 Write unit tests for filter edge cases (all approved, all dismissed, mixed, empty array)
  • 8.3 Write integration test verifying dismissed submissions remain in the database but are excluded from the filtered list