Files

11 KiB
Raw Permalink Blame History

Implementation Plan: CARD API Integration

Overview

This plan covers the remaining implementation work for the CARD API integration into the STEAM Security Dashboard. The CARD API helper module (backend/helpers/cardApi.js), environment variable configuration, and UAT test script are already built and validated. The remaining work focuses on the backend route module, server mounting, frontend CARD action UI, asset search panel, and property-based tests.

Tasks

  • 1. CARD API Helper Module (Already Complete)

    • backend/helpers/cardApi.js is built and UAT-tested with all exports: isConfigured, cardGet, cardPost, getTeams, getTeamAssets, getOwner, confirmAsset, declineAsset, redirectAsset, invalidateToken, testConnection
    • Token Manager handles OAuth Bearer token acquisition, 1-hour TTL caching, 60s refresh window, and automatic 401 retry
    • Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7
  • 2. Environment Variable Configuration (Already Complete)

    • backend/.env and backend/.env.example have CARD_API_URL, CARD_API_USER, CARD_API_PASS, CARD_SKIP_TLS configured with descriptive comments
    • Requirements: 3.1, 3.2, 3.3, 3.4
  • 3. UAT Test Script (Already Complete)

    • backend/scripts/card-uat-test.js exercises all 9 CARD API use cases and passes
    • Requirements: 1.1, 1.7, 2.1, 2.3, 2.6
  • 4. Backend CARD API Route Module

    • 4.1 Create backend/routes/cardApi.js with factory function createCardApiRouter(db, requireAuth)

      • Follow the existing atlas.js route pattern: import requireGroup from middleware, import logAudit from helpers, import CARD helper functions from helpers/cardApi.js
      • Add promise-based DB helpers (dbRun, dbGet) matching the atlas.js pattern
      • Protect all endpoints with requireAuth(db) and requireGroup('Admin', 'Standard_User')
      • Requirements: 4.1, 4.2
    • 4.2 Implement read-only proxy endpoints

      • GET /status — return { configured: isConfigured }; if not configured, return 503 with missing vars
      • GET /teams — proxy getTeams(), parse JSON response, forward to client
      • GET /teams/:teamName/assets — proxy getTeamAssets() with disposition (required), page, page_size (default 50) query params
      • GET /owner/:assetId — proxy getOwner(), return owner record
      • All proxy endpoints: return 503 if not configured, forward CARD API error status codes with JSON error body
      • Requirements: 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9
    • 4.3 Implement mutation endpoints (confirm, decline, redirect) with two-step update_token flow

      • POST /queue/:queueItemId/confirm — body: { teamName, assetId, comment? }
      • POST /queue/:queueItemId/decline — body: { teamName, assetId, comment? }
      • POST /queue/:queueItemId/redirect — body: { fromTeam, toTeam, assetId }
      • Validate queue item: exists, belongs to req.user.id, workflow_type = 'CARD', status = 'pending'; return 404 if not found/wrong user/wrong type, 400 if not pending
      • Validate required fields: teamName + assetId for confirm/decline; fromTeam + toTeam + assetId for redirect; return 400 if missing
      • Two-step flow: call getOwner(assetId) → extract update_token from owner.update_token → call mutation with token
      • On success: update queue item status = 'complete', return { success: true, cardResponse }
      • On failure: leave queue item as pending, return error
      • Requirements: 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 5.10, 5.11, 5.12, 5.13, 5.14, 5.15
    • 4.4 Implement error handling for CARD API responses

      • Map token endpoint errors: 401 → 401 auth failed, 403 → 403 access denied, 525 → 502 LDAP error
      • Map API call errors: 401 after retry → 401 token expired, 403 → 403 insufficient permissions
      • Catch unhandled errors → 502 with { error: 'CARD API request failed.', details }
      • Log all errors with [card-api] prefix via console.error
      • Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 8.10
    • 4.5 Implement audit logging for all CARD actions

      • card_confirm: entityType ivanti_todo_queue, entityId = queue item ID, details = { assetId, teamName, comment, cardStatus }
      • card_decline: same pattern with decline details
      • card_redirect: details = { assetId, fromTeam, toTeam, cardStatus }
      • card_search: entityType card_asset, entityId = team name, details = { disposition, resultCount }
      • card_action_failed: details = { actionType, assetId, error, cardStatus }
      • All entries include userId, username, ipAddress; use fire-and-forget semantics
      • Requirements: 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7
  • 5. Mount CARD route in server.js

    • 5.1 Add const createCardApiRouter = require('./routes/cardApi'); import to server.js alongside existing route imports
      • Mount with app.use('/api/card', createCardApiRouter(db, requireAuth)); after the Atlas route mount
      • Requirements: 4.10
  • 6. Checkpoint — Backend route verification

    • Ensure all tests pass, ask the user if questions arise.
  • 7. Frontend CARD Action UI

    • 7.1 Add CARD teams fetch and session-level caching to ReportingPage

      • Fetch /api/card/status on mount to check if CARD is configured
      • Fetch /api/card/teams once per session and cache in component state
      • Pass cardConfigured, cardTeams props down to QueuePanel
      • Requirements: 6.8, 6.9
    • 7.2 Add CARD action buttons (Confirm, Decline, Redirect) to queue items in QueuePanel

      • Render three action buttons on pending CARD queue items (workflow_type === 'CARD' and status === 'pending')
      • Disable buttons when CARD is not configured; show tooltip "CARD integration not configured"
      • Style buttons to match existing queue item action patterns (compact, inline)
      • Requirements: 6.1, 6.8
    • 7.3 Implement Confirm and Decline action forms

      • On Confirm/Decline button click: show inline form with team selection dropdown (populated from cached teams list) and optional comment text field
      • On form submit: POST to /api/card/queue/:queueItemId/confirm or /decline with { teamName, assetId: item.ip_address, comment }
      • While request is in flight: disable action buttons, show loading indicator on the queue item
      • On success: update queue item status to complete in local state without full refresh
      • On failure: display backend error message inline on the affected queue item
      • Requirements: 6.2, 6.3, 6.5, 6.6, 6.7
    • 7.4 Implement Redirect action form

      • On Redirect button click: show inline form with "From Team" dropdown and "To Team" dropdown (both from cached teams list)
      • On form submit: POST to /api/card/queue/:queueItemId/redirect with { fromTeam, toTeam, assetId: item.ip_address }
      • Same loading/success/error handling as confirm/decline
      • Requirements: 6.4, 6.5, 6.6, 6.7
  • 8. Frontend Asset Search Panel

    • 8.1 Create asset search interface accessible from the Ivanti Queue page
      • Add a "CARD Asset Search" button/section in the queue panel or as a collapsible panel
      • Include team selection dropdown (from cached teams) and disposition filter dropdown (confirmed, unconfirmed, declined, candidate)
      • On search: GET /api/card/teams/:teamName/assets?disposition=X&page_size=50
      • Display total asset count and results table with Asset_ID and identifying fields
      • Add pagination controls when total exceeds page size (increment page param)
      • Display error messages inline in the search results area on failure
      • Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7
  • 9. Checkpoint — Full integration verification

    • Ensure all tests pass, ask the user if questions arise.
  • 10. Property-based tests for CARD API correctness properties

    • * 10.1 Write property test for isConfigured environment variable logic

      • Property 1: isConfigured reflects environment variable presence
      • For any combination of the three required env vars being present/non-empty or absent/empty, isConfigured is true iff all three are present and non-empty
      • Create backend/__tests__/card-isConfigured.property.test.js using Jest + fast-check with 100+ iterations
      • Validates: Requirements 1.1, 3.3
    • * 10.2 Write property test for CARD API response shape consistency

      • Property 2: All CARD API responses have consistent shape
      • For any successful CARD API call, the resolved Promise contains { status: number, body: string }
      • Create backend/__tests__/card-response-shape.property.test.js
      • Validates: Requirements 1.7
    • * 10.3 Write property test for token acquisition error messages

      • Property 3: Token acquisition errors include status and body
      • For any non-success HTTP status and response body from the token endpoint, the rejected error message includes both the status code and body text
      • Create backend/__tests__/card-token-errors.property.test.js
      • Validates: Requirements 2.7
    • * 10.4 Write property test for CARD API error status code forwarding

      • Property 4: CARD API error status codes are forwarded through proxy
      • For any 4xx/5xx status from CARD API on a proxied request, the route returns that same status code with a JSON error body
      • Create backend/__tests__/card-error-forwarding.property.test.js
      • Validates: Requirements 4.9
    • * 10.5 Write property test for queue item validation on mutations

      • Property 5: Queue item validation rejects invalid states for mutations
      • For any mutation request where the queue item doesn't exist, wrong user, wrong workflow_type, or wrong status, the endpoint rejects with 404 or 400 without calling CARD API
      • Create backend/__tests__/card-queue-validation.property.test.js
      • Validates: Requirements 5.4, 5.5, 5.6
    • * 10.6 Write property test for mutation input validation

      • Property 6: Mutation input validation enforces required fields
      • For any mutation request missing required fields (teamName/assetId for confirm/decline; fromTeam/toTeam/assetId for redirect), the endpoint rejects with 400
      • Create backend/__tests__/card-input-validation.property.test.js
      • Validates: Requirements 5.11, 5.12, 5.13
    • * 10.7 Write property test for CARD mutation audit log entries

      • Property 7: CARD mutation audit entries contain required fields
      • For any mutation action, the audit log entry contains correct action name, entityType, entityId, userId, username, ipAddress, and details with assetId and CARD response status
      • Create backend/__tests__/card-audit-entries.property.test.js
      • Validates: Requirements 9.1, 9.2, 9.3, 9.6
  • 11. Final checkpoint — Ensure all tests pass

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

Notes

  • Tasks 13 are marked complete because backend/helpers/cardApi.js, .env/.env.example, and backend/scripts/card-uat-test.js are already built and UAT-tested
  • Tasks marked with * are optional property-based tests and can be skipped for faster MVP
  • Each task references specific requirements for traceability
  • The backend route module (Task 4) follows the existing atlas.js route pattern exactly
  • The frontend UI (Tasks 78) extends the existing QueuePanel in ReportingPage.js
  • Property tests use Jest + fast-check matching the existing test pattern in backend/__tests__/