Files
cve-dashboard/.kiro/specs/multi-item-jira-ticket/tasks.md
Jordan Ramos a61d254ff9 Sync .kiro/ from master — v2.2.0 release batch
New specs: archer-template-library, ccp-metrics-view-restructure,
compliance-list-stale-after-sidebar-edit, compliance-metric-estimated-resolution-date,
compliance-remediation-display-fix, flexible-jira-ticket-creation,
forecast-burndown-chart, granite-loader-export, ivanti-queue-clear-completed-fix,
multi-item-jira-ticket, queue-collapsible-sections, vendor-issue-type-dropdown

New steering: archer-template-gen.md

Updated: migration-registration-check hook, remediation-plan-history spec,
gitlab-workflow, tech, versioning steering files
2026-06-04 11:27:31 -06:00

125 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Implementation Plan: Multi-Item Jira Ticket Creation
## Overview
This plan implements multi-select on the Ivanti Queue page and a consolidation modal that creates a single Jira ticket from multiple selected queue items. The implementation proceeds from database migration → backend junction endpoints → frontend aggregation logic → frontend selection UI → consolidation modal → ticket link badges.
## Tasks
- [x] 1. Database migration for junction table
- [x] 1.1 Create migration file `backend/migrations/add_multi_item_jira_ticket.js`
- Verify `jira_tickets` and `ivanti_todo_queue` tables exist; exit with error if missing
- Create `jira_ticket_queue_items` table with columns: id (SERIAL PRIMARY KEY), jira_ticket_id (INTEGER NOT NULL REFERENCES jira_tickets(id)), queue_item_id (INTEGER NOT NULL REFERENCES ivanti_todo_queue(id)), created_at (TIMESTAMPTZ DEFAULT NOW())
- Add UNIQUE constraint on (jira_ticket_id, queue_item_id)
- Add index on queue_item_id
- Add index on jira_ticket_id
- Ensure full idempotency — safe to run multiple times
- _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5_
- [x] 2. Backend junction table endpoints
- [x] 2.1 Add `POST /api/jira-tickets/:id/queue-items` endpoint in `backend/routes/jiraTickets.js`
- Validate `queue_item_ids` is a non-empty array of integers
- Verify the jira_ticket exists
- Verify all referenced queue items exist
- Insert rows into `jira_ticket_queue_items` with ON CONFLICT DO NOTHING
- Return 201 with linked_count
- Require Admin or Standard_User group
- _Requirements: 5.3, 6.1, 6.2_
- [x] 2.2 Add `GET /api/ivanti/todo-queue/ticket-links` endpoint in `backend/routes/ivantiTodoQueue.js`
- Join `jira_ticket_queue_items` with `jira_tickets` to get ticket_key and url
- Filter by queue items belonging to the authenticated user
- Return a map of queue_item_id → { ticket_key, jira_url }
- _Requirements: 6.3, 6.4_
- [x] 3. Frontend aggregation utility functions
- [x] 3.1 Create `frontend/src/utils/jiraConsolidation.js` with pure functions
- `generateConsolidatedSummary(items)` — format: `[N findings] vendor - title`, truncated to 255 chars
- `generateConsolidatedDescription(items)` — structured description grouped by vendor
- `extractFirstCve(items)` — first CVE from first item with non-empty cves_json
- `extractCommonVendor(items)` — common vendor if all same, empty string otherwise
- _Requirements: 3.1, 3.2, 4.1, 4.2, 4.3, 4.4, 4.6, 4.7_
- [ ]* 3.2 Write property tests for aggregation functions (Properties 16)
- **Property 1: Summary format and truncation** — starts with `[N findings]`, at most 255 chars, contains correct vendor label
- **Property 2: Description includes all items** — every item's finding_title appears in output
- **Property 3: Description groups by vendor** — items with same vendor are contiguous
- **Property 4: Description header contains count** — output contains the item count
- **Property 5: First CVE extraction** — returns first CVE from first item with CVEs, or empty string
- **Property 6: Common vendor extraction** — returns vendor when all same, empty when different
- **Validates: Requirements 3.1, 3.2, 4.1, 4.2, 4.3, 4.4, 4.6, 4.7**
- File: `backend/__tests__/jira-consolidation-aggregation.property.test.js`
- [x] 4. Frontend multi-select mode on Ivanti Queue page
- [x] 4.1 Add selection mode toggle and checkbox UI to `frontend/src/components/pages/IvantiQueuePage.js`
- Add "Select" toggle button to page toolbar
- Show checkboxes on each queue item row when selection mode active
- Add "Select All" checkbox in table header
- Display selection count indicator
- Clear selections when selection mode deactivated
- Preserve selections on scroll/re-render within same session
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6_
- [x] 4.2 Add floating action bar with "Create Jira Ticket" button
- Render floating bar when selection mode active and at least 1 item selected
- Disable "Create Jira Ticket" button when no items selected
- Route to existing single-item modal when exactly 1 item selected
- Route to new Consolidation Modal when 2+ items selected
- _Requirements: 2.1, 2.2, 2.3, 2.4_
- [x] 5. Frontend Consolidation Modal
- [x] 5.1 Create `frontend/src/components/ConsolidationModal.js`
- Accept selected queue items as props
- Call aggregation functions to pre-populate summary, description, cve_id, vendor
- Lock source_context to `ivanti_queue` (read-only display)
- Display item count in modal header/subtitle
- Render scrollable preview list of selected items (finding_title + hostname)
- Allow removing individual items from selection (minimum 2 required)
- Disable submit and show message when fewer than 2 items remain
- Editable summary field with required validation (max 255 chars)
- Editable description textarea
- Editable CVE ID and Vendor fields (optional)
- On submit: POST to create-in-jira, then POST to junction endpoint
- On success: close modal, show success toast, trigger queue page refresh
- On error: display error message, preserve form values
- _Requirements: 3.1, 3.2, 3.3, 3.4, 4.1, 4.5, 5.1, 5.2, 5.4, 5.5, 8.1, 8.2, 8.3, 8.4, 8.5_
- [x] 6. Frontend ticket link badges on queue items
- [x] 6.1 Fetch and display ticket link badges on Ivanti Queue page
- On page load, fetch `GET /api/ivanti/todo-queue/ticket-links`
- For each queue item with an association, render a ticket key badge (e.g., "VULN-789")
- Clicking badge opens Jira URL in new tab
- Refresh links after successful consolidated ticket creation
- _Requirements: 6.3, 6.4, 6.5_
- [ ] 7. Backend property test for junction insert invariant
- [ ]* 7.1 Write property test for junction row count (Property 7)
- **Property 7: Junction table row count equals selected item count** — for N items, exactly N rows inserted
- **Validates: Requirements 5.3, 6.2**
- File: `backend/__tests__/jira-consolidation-junction.property.test.js`
- [x] 8. Final checkpoint
- Ensure all tests pass, ask the user if questions arise.
## Notes
- Tasks marked with `*` are optional property-based tests that can be skipped for faster MVP
- The existing `POST /api/jira-tickets/create-in-jira` endpoint is reused without modification
- The aggregation functions are pure and extracted into a utility module for easy testing
- The junction table insert happens as a second request after ticket creation — if it fails, the ticket still exists in Jira (partial success scenario handled with warning)
- The Consolidation Modal is a separate component from the existing Creation Modal to avoid overcomplicating the single-item flow
## Task Dependency Graph
```json
{
"waves": [
{ "id": 0, "tasks": ["1.1"] },
{ "id": 1, "tasks": ["2.1", "2.2", "3.1"] },
{ "id": 2, "tasks": ["3.2", "4.1"] },
{ "id": 3, "tasks": ["4.2", "5.1"] },
{ "id": 4, "tasks": ["6.1", "7.1"] }
]
}
```