Files
cve-dashboard/.kiro/specs/jira-api-compliance/tasks.md
root 27192dd69f WIP: Dashboard redesign — design system overhaul and component updates
Frontend redesign in progress: updated styles, layout, and components
across all pages to align with new design system. Includes Jira API
compliance specs, property tests, and load test script.
2026-04-29 14:20:23 +00:00

10 KiB

Implementation Plan

  • 1. Write bug condition exploration test

    • Property 1: Bug Condition — Jira API Compliance Violations
    • CRITICAL: This test MUST FAIL on unfixed code — failure confirms the bugs exist
    • DO NOT attempt to fix the test or the code when it fails
    • NOTE: This test encodes the expected behavior — it will validate the fix when it passes after implementation
    • GOAL: Surface counterexamples that demonstrate the three compliance violations
    • Scoped PBT Approach: Scope properties to the three concrete bug conditions:
      1. searchIssues() sends POST instead of GET — generate random JQL strings and assert the HTTP method captured is GET and the request path starts with /rest/api/2/search? with query parameters (not a JSON body)
      2. getIssue() sends a single-issue GET to /rest/api/2/issue/{key} — generate random issue keys and assert the request path contains /rest/api/2/search (not /rest/api/2/issue/)
      3. searchIssuesByKeys() builds JQL without project = — generate random arrays of issue keys and assert the JQL string passed to the search contains project =
    • Mock jiraRequest to capture HTTP method, URL path, and body arguments without making real HTTP calls
    • Use fast-check arbitraries to generate JQL strings, issue keys (e.g., fc.tuple(fc.stringMatching(/^[A-Z]{2,6}$/), fc.integer({ min: 1, max: 99999 })) for KEY-123 patterns), and key arrays
    • Test file: backend/__tests__/jira-api-compliance.property.test.js
    • Run test on UNFIXED code
    • EXPECTED OUTCOME: Test FAILS (this is correct — it proves the bugs exist)
    • Document counterexamples found: searchIssues() uses POST, getIssue() hits /rest/api/2/issue/{key}, searchIssuesByKeys() JQL lacks project =
    • Mark task complete when test is written, run, and failure is documented
    • Requirements: 1.1, 1.2, 1.3
  • 2. Write preservation property tests (BEFORE implementing fix)

    • Property 2: Preservation — Unchanged Jira API Functions
    • IMPORTANT: Follow observation-first methodology
    • Observe behavior on UNFIXED code for non-buggy functions:
      • createIssue({ project: { key: 'TEST' }, summary: 'x', issuetype: { name: 'Task' } }) sends POST to /rest/api/2/issue with JSON body containing { fields: {...} }
      • updateIssue('TEST-1', { summary: 'y' }) sends PUT to /rest/api/2/issue/TEST-1 with JSON body containing { fields: {...} }
      • addComment('TEST-1', 'comment text') sends POST to /rest/api/2/issue/TEST-1/comment with JSON body containing { body: 'comment text' }
      • transitionIssue('TEST-1', '5') sends POST to /rest/api/2/issue/TEST-1/transitions with JSON body containing { transition: { id: '5' } }
      • getTransitions('TEST-1') sends GET to /rest/api/2/issue/TEST-1/transitions
      • testConnection() sends GET to /rest/api/2/myself
    • Write property-based tests using fast-check that verify for all generated inputs:
      1. createIssue() always sends POST /rest/api/2/issue with { fields } body — generate random field objects
      2. updateIssue() always sends PUT /rest/api/2/issue/{key} with { fields } body — generate random keys and field objects
      3. addComment() always sends POST /rest/api/2/issue/{key}/comment with { body } — generate random keys and comment strings
      4. transitionIssue() always sends POST /rest/api/2/issue/{key}/transitions with { transition: { id } } — generate random keys and transition IDs
      5. getTransitions() always sends GET /rest/api/2/issue/{key}/transitions — generate random keys
      6. testConnection() always sends GET /rest/api/2/myself
      7. Response shape: searchIssues() returns { ok, data: { total, issues } } and getIssue() returns { ok, data: <issue> } — verify shape is preserved
    • Mock jiraRequest to capture method, path, body and return appropriate mock responses
    • Test file: backend/__tests__/jira-api-preservation.property.test.js
    • Verify tests pass on UNFIXED code
    • EXPECTED OUTCOME: Tests PASS (this confirms baseline behavior to preserve)
    • Mark task complete when tests are written, run, and passing on unfixed code
    • Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10
  • 3. Fix the core API helper (backend/helpers/jiraApi.js)

    • 3.1 Convert searchIssues() from POST to GET with query parameters

      • Replace jiraPost('/rest/api/2/search', body) with jiraGet('/rest/api/2/search?jql=...&fields=...&maxResults=...&startAt=...')
      • URL-encode JQL string with encodeURIComponent(jql)
      • Comma-join and encode fields array with encodeURIComponent(fields.join(','))
      • Encode maxResults and startAt as query parameters
      • Remove the JSON body object { jql, startAt, maxResults, fields }
      • Preserve the res.status === 200 check and JSON.parse(res.body) response parsing
      • Preserve the { ok, data } return shape
      • Bug_Condition: searchIssues uses POST /rest/api/2/search with JSON body
      • Expected_Behavior: searchIssues uses GET /rest/api/2/search?jql=&fields=&maxResults=&startAt=
      • Preservation: Response shape { ok, data: { total, issues } } unchanged
      • Requirements: 2.1
    • 3.2 Add project scoping to searchIssuesByKeys() JQL

      • Change JQL from key in (${keyList}) AND updated >= -24h to key in (${keyList}) AND updated >= -24h AND project = ${JIRA_PROJECT_KEY}
      • JIRA_PROJECT_KEY is already available in module scope
      • Bug_Condition: searchIssuesByKeys JQL lacks project = clause
      • Expected_Behavior: JQL includes project = JIRA_PROJECT_KEY
      • Preservation: Return shape and searchIssues delegation unchanged
      • Requirements: 2.2
    • 3.3 Refactor getIssue() to delegate to searchIssues() via JQL

      • Replace jiraGet('/rest/api/2/issue/${encodeURIComponent(issueKey)}?fields=...') with a call to searchIssues() using JQL key = "${issueKey}" AND project = ${JIRA_PROJECT_KEY} and maxResults: 1
      • Extract data.issues[0] from search results to return as { ok: true, data: <issue> }
      • Return { ok: false, status: 404, body: 'Issue not found' } when search returns empty results
      • Preserve the { ok, data: <single-issue> } return shape for callers
      • Bug_Condition: getIssue sends GET /rest/api/2/issue/{key} (single-issue GET)
      • Expected_Behavior: getIssue delegates to searchIssues with JQL key = "{key}" AND project = KEY
      • Preservation: Return shape { ok, data: { key, fields } } unchanged
      • Requirements: 2.3
    • 3.4 Verify bug condition exploration test now passes

      • Property 1: Expected Behavior — Jira API Compliance Violations
      • IMPORTANT: Re-run the SAME test from task 1 — do NOT write a new test
      • The test from task 1 encodes the expected behavior
      • When this test passes, it confirms the expected behavior is satisfied
      • Run npx jest backend/__tests__/jira-api-compliance.property.test.js --no-cache
      • EXPECTED OUTCOME: Test PASSES (confirms bugs are fixed)
      • Requirements: 2.1, 2.2, 2.3
    • 3.5 Verify preservation tests still pass

      • Property 2: Preservation — Unchanged Jira API Functions
      • IMPORTANT: Re-run the SAME tests from task 2 — do NOT write new tests
      • Run npx jest backend/__tests__/jira-api-preservation.property.test.js --no-cache
      • EXPECTED OUTCOME: Tests PASS (confirms no regressions)
      • Confirm all unchanged functions still produce the same HTTP method, path, and body
  • 4. Update the UAT test script (backend/scripts/jira-uat-test.js)

    • 4.1 Update test case 3 name to reflect JQL-based pattern

      • Change '3. Get Single Issue (GET /issue/{key})' to '3. Get Single Issue (JQL search)'
      • The test body calls jiraApi.getIssue() which now delegates to JQL search — no logic change needed in the test function itself
      • Requirements: 2.4
    • 4.2 Update test case 8 name to reflect GET method

      • Change '8. JQL Search (POST /search)' to '8. JQL Search (GET /search)'
      • Add project-scoped JQL to the test: include AND project = ${jiraApi.JIRA_PROJECT_KEY} in the JQL string passed to searchIssues()
      • Requirements: 2.5
    • 4.3 Update test case 9 to verify project scoping

      • Add a log entry or assertion that the bulk key search includes project scoping
      • The underlying searchIssuesByKeys() now includes project = <KEY> — the test validates the function works correctly with the compliant JQL
      • Requirements: 2.5
  • 5. Update the API documentation (docs/jira-api-use-cases.md)

    • 5.1 Update compliance summary table

      • Change "Bulk reads via JQL" row endpoint from POST /rest/api/2/search to GET /rest/api/2/search
      • Add a row for "Single-issue fetch" describing JQL-based lookup via GET /rest/api/2/search?jql=key="KEY"&...
      • Requirements: 2.6, 2.7
    • 5.2 Update Use Case 3 (Get Single Issue)

      • Change endpoint from GET /rest/api/2/issue/{issueKey}?fields=... to GET /rest/api/2/search?jql=key="ISSUE-KEY" AND project=<KEY>&fields=...&maxResults=1
      • Update the description to explain the JQL-based pattern
      • Requirements: 2.7
    • 5.3 Update Use Case 8 (JQL Search / Bulk Sync)

      • Change endpoint from POST /rest/api/2/search to GET /rest/api/2/search?jql=...&fields=...&maxResults=...&startAt=...
      • Update JQL pattern to include project = <KEY> scoping
      • Requirements: 2.6
    • 5.4 Update Use Case 9 (Issue Lookup)

      • Change endpoint from GET /rest/api/2/issue/{issueKey}?fields=... to GET /rest/api/2/search?jql=key="ISSUE-KEY" AND project=<KEY>&fields=...&maxResults=1
      • Update the description to match the JQL-based lookup pattern
      • Requirements: 2.7
  • 6. Checkpoint — Ensure all tests pass

    • Run npx jest backend/__tests__/jira-api-compliance.property.test.js --no-cache — all bug condition tests pass
    • Run npx jest backend/__tests__/jira-api-preservation.property.test.js --no-cache — all preservation tests pass
    • Run npx jest --no-cache — all existing tests in the project still pass
    • Ensure all tests pass, ask the user if questions arise.