- Add migration to add hostname column to ivanti_todo_queue table - Update POST and batch POST endpoints to accept and store hostname - Pass hostName from findings data when adding items to queue - Display hostname and IP address in CARD queue section - Display hostname and IP address in vendor (FP/Archer) queue sections
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:
- Database — A migration adds a
hostname TEXTcolumn toivanti_todo_queue. - Backend API — The POST (single + batch) endpoints accept and store an optional
hostnamefield. The GET endpoint already usesSELECT *, so hostname is returned automatically once the column exists. - Frontend — The
addToQueueandsubmitBatchfunctions passfinding.hostNameashostname. 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.dbviasqlite3 - Runs
ALTER TABLE ivanti_todo_queue ADD COLUMN hostname TEXT - Catches
duplicate column nameerror to make it idempotent - Closes the database connection
Backend Route: backend/routes/ivantiTodoQueue.js
Changes to two endpoints:
POST / (single-item)
- Extract
hostnamefromreq.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
findingsarray, extracthostnamefromf.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 || nullto the POST body
submitBatch function
- Add
hostname: f.hostName || nullto each finding object infindingsPayload
QueuePanel rendering (per item)
For CARD items, the content <div> currently shows:
finding_idip_address(if present)
New rendering for CARD items:
finding_idhostname(if present)ip_address(if present)
For vendor-grouped items (FP/Archer), the content <div> currently shows:
finding_id- CVE list (if present)
New rendering for vendor-grouped items:
finding_id- CVE list (if present)
hostname(if present)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 response — hostname 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.