Files
cve-dashboard/.kiro/specs/queue-hostname-ip-display/design.md

6.5 KiB

Design Document: Queue Hostname & IP Display

Overview

This feature adds hostname tracking to the Ivanti todo queue. Currently the queue stores ip_address but not hostname. The change spans three layers:

  1. Database — A migration adds a hostname TEXT column to ivanti_todo_queue.
  2. Backend API — The POST (single + batch) endpoints accept and store an optional hostname field. The GET endpoint already uses SELECT *, so hostname is returned automatically once the column exists.
  3. Frontend — The addToQueue and submitBatch functions pass finding.hostName as hostname. The QueuePanel renders hostname and IP address for both CARD and vendor-grouped (FP/Archer) sections.

The change is additive and backward-compatible. Existing rows get NULL for hostname. No existing behavior changes unless both hostname and ip_address are present.

Architecture

The data flows through three layers in a straight pipeline:

flowchart LR
    A[Ivanti Finding<br/>hostName, ipAddress] -->|POST /todo-queue| B[Express Route<br/>ivantiTodoQueue.js]
    B -->|INSERT hostname, ip_address| C[SQLite<br/>ivanti_todo_queue]
    C -->|SELECT *| B
    B -->|GET response| D[QueuePanel<br/>ReportingPage.js]

No new services, tables, or route modules are introduced. The migration script is a standalone Node.js file following the existing pattern in backend/migrations/.

Components and Interfaces

Migration Script: backend/migrations/add_todo_queue_hostname.js

Follows the exact pattern of add_todo_queue_ip_address.js:

  • Opens cve_database.db via sqlite3
  • Runs ALTER TABLE ivanti_todo_queue ADD COLUMN hostname TEXT
  • Catches duplicate column name error to make it idempotent
  • Closes the database connection

Backend Route: backend/routes/ivantiTodoQueue.js

Changes to two endpoints:

POST / (single-item)

  • Extract hostname from req.body
  • Sanitize: if present and a string, trim and slice to 255 chars; otherwise null
  • Add to the INSERT column list and parameter array

POST /batch

  • For each finding in the findings array, extract hostname from f.hostname
  • Same sanitization as single-item
  • Add to the per-row INSERT column list and parameter array

GET / — No code change needed. SELECT * already returns all columns.

PUT /:id — No change. Hostname is set at insert time and not editable.

Frontend: ReportingPage.js

addToQueue function

  • Add hostname: finding.hostName || null to the POST body

submitBatch function

  • Add hostname: f.hostName || null to each finding object in findingsPayload

QueuePanel rendering (per item)

For CARD items, the content <div> currently shows:

  1. finding_id
  2. ip_address (if present)

New rendering for CARD items:

  1. finding_id
  2. hostname (if present)
  3. ip_address (if present)

For vendor-grouped items (FP/Archer), the content <div> currently shows:

  1. finding_id
  2. CVE list (if present)

New rendering for vendor-grouped items:

  1. finding_id
  2. CVE list (if present)
  3. hostname (if present)
  4. ip_address (if present)

Both hostname and IP use the same monospace styling at 0.68rem / 0.62rem with muted colors consistent with the existing design system.

Data Models

ivanti_todo_queue table (after migration)

Column Type Nullable Notes
id INTEGER NO PRIMARY KEY AUTOINCREMENT
user_id INTEGER NO FK → users(id)
finding_id TEXT NO
finding_title TEXT YES max 500 chars
cves_json TEXT YES JSON array string
ip_address TEXT YES max 64 chars
hostname TEXT YES max 255 chars (new)
vendor TEXT NO
workflow_type TEXT NO FP, Archer, or CARD
status TEXT NO pending or complete
created_at DATETIME NO DEFAULT CURRENT_TIMESTAMP
updated_at DATETIME NO DEFAULT CURRENT_TIMESTAMP

API Request/Response Changes

POST /api/ivanti/todo-queue body — adds optional field:

{
  "finding_id": "...",
  "finding_title": "...",
  "cves": [],
  "ip_address": "...",
  "hostname": "server01.example.com",
  "vendor": "...",
  "workflow_type": "CARD"
}

POST /api/ivanti/todo-queue/batch body — adds optional field per finding:

{
  "findings": [
    { "finding_id": "...", "ip_address": "...", "hostname": "server01.example.com" }
  ],
  "workflow_type": "FP",
  "vendor": "VendorName"
}

GET responsehostname field included automatically via SELECT *:

{
  "id": 1,
  "finding_id": "...",
  "hostname": "server01.example.com",
  "ip_address": "10.0.0.1",
  "..."
}

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

Property 1: Hostname storage round-trip

For any valid hostname string (up to 255 characters), storing it via the queue API (single or batch endpoint) and then retrieving it via GET should return the exact same trimmed string. When the hostname is omitted, null, or empty, the stored and returned value should be null.

Validates: Requirements 2.1, 2.2, 2.3, 2.4

Property 2: Hostname display presence

For any queue item with a non-null hostname value, the rendered QueuePanel output should contain the hostname text, regardless of whether the item is a CARD item or a vendor-grouped (FP/Archer) item.

Validates: Requirements 4.1, 5.1

Error Handling

Scenario Handling
Migration run when column already exists Catch duplicate column name SQLite error, log skip message, exit cleanly
hostname field is not a string Treat as null — store NULL in database
hostname exceeds 255 characters Truncate to 255 characters via .slice(0, 255)
hostname is undefined/null/empty string Store NULL in database
GET returns item with null hostname Frontend conditionally renders — no hostname line shown
GET returns item with null ip_address and null hostname CARD: show only finding_id. Vendor: show finding_id + CVEs only

No new error codes or HTTP status changes are introduced. The hostname field is optional and its absence is a normal case, not an error.

Testing Strategy

Testing is out of scope for this feature. Manual verification will be performed after implementation.