11 KiB
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.jsis 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/.envandbackend/.env.examplehaveCARD_API_URL,CARD_API_USER,CARD_API_PASS,CARD_SKIP_TLSconfigured with descriptive comments- Requirements: 3.1, 3.2, 3.3, 3.4
-
3. UAT Test Script (Already Complete)
backend/scripts/card-uat-test.jsexercises 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.jswith factory functioncreateCardApiRouter(db, requireAuth)- Follow the existing
atlas.jsroute pattern: importrequireGroupfrom middleware, importlogAuditfrom helpers, import CARD helper functions fromhelpers/cardApi.js - Add promise-based DB helpers (
dbRun,dbGet) matching the atlas.js pattern - Protect all endpoints with
requireAuth(db)andrequireGroup('Admin', 'Standard_User') - Requirements: 4.1, 4.2
- Follow the existing
-
4.2 Implement read-only proxy endpoints
GET /status— return{ configured: isConfigured }; if not configured, return 503 with missing varsGET /teams— proxygetTeams(), parse JSON response, forward to clientGET /teams/:teamName/assets— proxygetTeamAssets()withdisposition(required),page,page_size(default 50) query paramsGET /owner/:assetId— proxygetOwner(), 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+assetIdfor confirm/decline;fromTeam+toTeam+assetIdfor redirect; return 400 if missing - Two-step flow: call
getOwner(assetId)→ extractupdate_tokenfromowner.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 viaconsole.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: entityTypeivanti_todo_queue, entityId = queue item ID, details ={ assetId, teamName, comment, cardStatus }card_decline: same pattern with decline detailscard_redirect: details ={ assetId, fromTeam, toTeam, cardStatus }card_search: entityTypecard_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
- Mount with
- 5.1 Add
-
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/statuson mount to check if CARD is configured - Fetch
/api/card/teamsonce per session and cache in component state - Pass
cardConfigured,cardTeamsprops down toQueuePanel - Requirements: 6.8, 6.9
- Fetch
-
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'andstatus === '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
- Render three action buttons on pending CARD queue items (
-
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/confirmor/declinewith{ 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
completein 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/redirectwith{ 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
pageparam) - 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
- 8.1 Create asset search interface accessible from the Ivanti Queue page
-
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,
isConfiguredistrueiff all three are present and non-empty - Create
backend/__tests__/card-isConfigured.property.test.jsusing 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
actionname,entityType,entityId,userId,username,ipAddress, anddetailswithassetIdand 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 1–3 are marked complete because
backend/helpers/cardApi.js,.env/.env.example, andbackend/scripts/card-uat-test.jsare 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.jsroute pattern exactly - The frontend UI (Tasks 7–8) extends the existing
QueuePanelinReportingPage.js - Property tests use Jest + fast-check matching the existing test pattern in
backend/__tests__/