Files
cve-dashboard/.kiro/specs/flexible-jira-ticket-creation/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

140 lines
9.1 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: Flexible Jira Ticket Creation
## Overview
This plan implements flexible Jira ticket creation by making CVE ID and Vendor optional, adding source_context tracking, updating the creation modal, exposing "Create Jira Ticket" actions from Ivanti queue and Archer detail views, and updating the ticket list with source context display and filtering. The implementation proceeds from database migration → backend validation → frontend modal updates → integration points → list view enhancements.
## Tasks
- [x] 1. Database migration for schema changes
- [x] 1.1 Create migration file `backend/migrations/add_flexible_jira_ticket_creation.js`
- Drop NOT NULL constraint on `cve_id` column
- Drop NOT NULL constraint on `vendor` column
- Add `source_context TEXT DEFAULT 'manual'` column with `IF NOT EXISTS`
- Add CHECK constraint for allowed source_context values (`cve`, `archer`, `ivanti_queue`, `email`, `manual`) with idempotent guard
- Backfill existing rows with `source_context = 'manual'` where NULL
- Add index on `source_context` column
- Verify `jira_tickets` table exists before proceeding; exit with error if missing
- Ensure full idempotency — safe to run multiple times
- _Requirements: 1.5, 2.4, 3.1, 3.5, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_
- [x] 2. Update backend validation and creation endpoint
- [x] 2.1 Update `POST /api/jira-tickets/create-in-jira` validation logic in `backend/routes/jiraTickets.js`
- Make `cve_id` optional: accept absent, null, or empty string as NULL; validate format `CVE-YYYY-NNNN+` only when non-empty
- Make `vendor` optional: accept absent, null, empty, or whitespace-only as NULL; trim and validate max 200 chars when non-empty
- Add `source_context` validation: must be in allowed set if provided, default to `manual` if absent
- Update INSERT query to include `source_context` column
- Update 201 response to include `source_context` in returned JSON
- Update audit log details to include `source_context`
- _Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 2.2, 2.3, 2.5, 3.2, 3.3, 3.4_
- [x] 2.2 Update `PUT /api/jira-tickets/:id` to reject source_context changes
- If request body contains `source_context` field, return 400 with "source_context is immutable after creation"
- _Requirements: 3.6_
- [x] 2.3 Update `GET /api/jira-tickets` to include source_context in response
- Ensure `source_context` is included in SELECT query and returned in ticket objects
- _Requirements: 3.4_
- [ ]* 2.4 Write property tests for CVE ID validation (Property 1 and Property 2)
- **Property 1: CVE ID validation and storage** — For any payload with absent/null/empty cve_id, service accepts and stores NULL; for valid CVE format, stores exact value
- **Property 2: Invalid CVE ID rejection** — For any non-empty string not matching `CVE-YYYY-NNNN+`, service rejects with 400
- **Validates: Requirements 1.1, 1.2, 1.3, 1.4**
- File: `backend/__tests__/jira-flexible-cve-validation.property.test.js`
- [ ]* 2.5 Write property tests for Vendor validation (Property 3 and Property 4)
- **Property 3: Vendor validation and storage** — For any payload with absent/null/empty/whitespace vendor, stores NULL; for 1200 char string after trim, stores trimmed value
- **Property 4: Over-length vendor rejection** — For any string exceeding 200 chars after trim, service rejects with validation error
- **Validates: Requirements 2.1, 2.2, 2.3**
- File: `backend/__tests__/jira-flexible-vendor-validation.property.test.js`
- [ ]* 2.6 Write property tests for source_context validation (Property 5, Property 6, Property 7)
- **Property 5: Invalid source_context rejection** — For any string not in allowed set, service rejects with 400
- **Property 6: source_context round-trip persistence** — For any valid source_context, creating then fetching returns same value
- **Property 7: source_context immutability** — For any existing ticket, update with source_context field is rejected with 400
- **Validates: Requirements 3.3, 3.4, 3.6**
- File: `backend/__tests__/jira-flexible-source-context.property.test.js`
- [x] 3. Checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 4. Update frontend Creation Modal for optional fields
- [x] 4.1 Update the create Jira ticket modal in `frontend/src/components/pages/JiraPage.js`
- Change CVE ID label to "CVE ID (optional)" with placeholder "e.g. CVE-2024-12345"
- Change Vendor label to "Vendor (optional)" with placeholder "e.g. Microsoft"
- Add Source Context dropdown with options: CVE → `cve`, Archer Request → `archer`, Ivanti Queue → `ivanti_queue`, Email → `email`, Manual → `manual`; no default selection
- Allow form submission when CVE ID and Vendor are both empty
- Keep Summary as required with inline error on empty submit (max 255 chars)
- Send `source_context` in payload only when selected; omit if no selection (backend defaults to `manual`)
- Support pre-populated field values and locked source_context (read-only when set externally)
- Preserve form field values on API error for retry
- _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 5.6, 6.5_
- [x] 5. Add "Create Jira Ticket" action from Ivanti Queue
- [x] 5.1 Add "Create Jira Ticket" button to Ivanti queue items in `frontend/src/components/pages/IvantiTodoQueuePage.js`
- Add button/action to each queue item row
- On click, open Creation Modal with: summary pre-populated from `finding_title` (truncated to 255 chars), source_context locked to `ivanti_queue`, cve_id from first element of `cves_json` (if non-empty), vendor from queue item's vendor (if present)
- Leave CVE ID blank if `cves_json` is empty or null
- _Requirements: 5.1, 5.2, 5.3, 5.4, 5.5_
- [ ]* 5.2 Write property test for summary truncation (Property 8)
- **Property 8: Summary pre-population truncation from Ivanti queue** — For any finding_title of arbitrary length, pre-populated summary is at most 255 chars and equals first 255 chars of finding_title
- **Validates: Requirements 5.2**
- File: `backend/__tests__/jira-flexible-summary-truncation.property.test.js`
- [x] 6. Add "Create Jira Ticket" action from Archer Detail View
- [x] 6.1 Add "Create Jira Ticket" button to Archer ticket detail view in `frontend/src/components/pages/ArcherPage.js`
- Show button only for users with editor or admin role
- On click, open Creation Modal with: summary pre-populated with `exc_number` (e.g., "EXC-1234"), source_context locked to `archer`, cve_id from Archer ticket's cve_id (if present), vendor from Archer ticket's vendor (if present)
- _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5_
- [x] 7. Update ticket list with source context display and filtering
- [x] 7.1 Add source context badge column to ticket list in `frontend/src/components/pages/JiraPage.js`
- Add "Source" column between Vendor and Summary columns
- Display color-coded badge per source_context value: cve → blue (#0EA5E9), archer → purple (#8B5CF6), ivanti_queue → amber (#F59E0B), email → green (#10B981), manual → gray (#94A3B8)
- Display "CVE" badge (blue) for null/empty source_context (legacy tickets)
- _Requirements: 8.1, 8.2_
- [x] 7.2 Add source context dropdown filter to ticket list
- Add dropdown filter consistent with existing status filter pattern
- Include "All" option showing all tickets plus one option per distinct source_context value
- _Requirements: 8.3_
- [x] 7.3 Include source_context in ticket search
- Add source_context to the set of searchable fields alongside ticket_key, cve_id, vendor, and summary
- _Requirements: 8.4_
- [ ]* 7.4 Write property test for search includes source_context (Property 9)
- **Property 9: Search includes source_context** — For any ticket whose source_context contains the search term as a substring, that ticket appears in filtered results
- **Validates: Requirements 8.4**
- File: `backend/__tests__/jira-flexible-search-source-context.property.test.js`
- [x] 8. Final checkpoint - Ensure all tests pass
- 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
- Checkpoints ensure incremental validation
- Property tests validate universal correctness properties from the design document
- Unit tests validate specific examples and edge cases
- The migration must run before backend changes are tested against a real database
- The Creation Modal is shared across all three entry points (Jira page, Ivanti queue, Archer detail) — task 4.1 builds the reusable foundation, tasks 5.1 and 6.1 wire it from their respective contexts
## Task Dependency Graph
```json
{
"waves": [
{ "id": 0, "tasks": ["1.1"] },
{ "id": 1, "tasks": ["2.1", "2.2", "2.3"] },
{ "id": 2, "tasks": ["2.4", "2.5", "2.6"] },
{ "id": 3, "tasks": ["4.1"] },
{ "id": 4, "tasks": ["5.1", "6.1"] },
{ "id": 5, "tasks": ["5.2", "7.1", "7.2", "7.3"] },
{ "id": 6, "tasks": ["7.4"] }
]
}
```