Update README to v2.2.0 — document all features since initial release
Rewrites the README from v1.0.0 to reflect current codebase state: - Add TOC, full feature descriptions for 20+ features - Add complete Configuration table (30+ env vars) - Add Database Schema table (26 tables) - Add Migrations table (46 migration files) - Add API Reference with all route groups - Add CI/CD Pipeline section - Add Troubleshooting section (Symptom/Cause/Fix format) - Update Project Structure with all routes, components, pages - Update Tech Stack and Documentation links
This commit is contained in:
851
README.md
851
README.md
@@ -1,6 +1,44 @@
|
|||||||
# STEAM Security Dashboard v1.0.0
|
# STEAM Security Dashboard v2.2.0
|
||||||
|
|
||||||
A self-hosted vulnerability management dashboard for the NTS-AEO-STEAM and NTS-AEO-ACCESS-ENG business units. Centralises CVE tracking, Ivanti host finding triage, AEO compliance posture, FP/Archer/CARD exception workflows, and internal documentation in a single interface.
|
A self-hosted vulnerability management dashboard for the NTS-AEO-STEAM, NTS-AEO-ACCESS-ENG, NTS-AEO-ACCESS-OPS, and NTS-AEO-INTELDEV business units. Centralises CVE tracking, Ivanti host finding triage, AEO compliance posture monitoring, CCP Metrics cross-org compliance reporting, FP/Archer/CARD/GRANITE/DECOM exception workflows, CARD asset ownership management, Granite Loader Sheet generation, Jira ticket management, and internal documentation in a single interface.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Quick Start](#quick-start)
|
||||||
|
- [Features](#features)
|
||||||
|
- [Home — CVE Management](#home--cve-management)
|
||||||
|
- [Reporting — Ivanti Host Findings](#reporting--ivanti-host-findings)
|
||||||
|
- [Ivanti Queue — Workflow Staging](#ivanti-queue--workflow-staging)
|
||||||
|
- [FP Workflow Submission](#fp-workflow-submission)
|
||||||
|
- [Archer Tickets](#archer-tickets)
|
||||||
|
- [Archer Template Library](#archer-template-library)
|
||||||
|
- [AEO Compliance](#aeo-compliance)
|
||||||
|
- [CCP Metrics — Multi-Vertical Compliance](#ccp-metrics--multi-vertical-compliance)
|
||||||
|
- [CARD Asset Ownership](#card-asset-ownership)
|
||||||
|
- [Granite Loader Sheet](#granite-loader-sheet)
|
||||||
|
- [Atlas Action Plans](#atlas-action-plans)
|
||||||
|
- [Jira Integration](#jira-integration)
|
||||||
|
- [Finding Archive Tracking](#finding-archive-tracking)
|
||||||
|
- [Findings Trend](#findings-trend)
|
||||||
|
- [Knowledge Base](#knowledge-base)
|
||||||
|
- [Exports](#exports)
|
||||||
|
- [In-App Notifications](#in-app-notifications)
|
||||||
|
- [Feedback — GitLab Integration](#feedback--gitlab-integration)
|
||||||
|
- [Access Control](#access-control)
|
||||||
|
- [Project Structure](#project-structure)
|
||||||
|
- [Tech Stack](#tech-stack)
|
||||||
|
- [Configuration](#configuration)
|
||||||
|
- [Database Schema](#database-schema)
|
||||||
|
- [Migrations](#migrations)
|
||||||
|
- [API Reference](#api-reference)
|
||||||
|
- [CI/CD Pipeline](#cicd-pipeline)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -34,7 +72,7 @@ cp backend/.env.example backend/.env
|
|||||||
# openssl rand -base64 32
|
# openssl rand -base64 32
|
||||||
```
|
```
|
||||||
|
|
||||||
See `backend/.env.example` for all available options including `DATABASE_URL`, Ivanti API, Jira, and Atlas integration keys.
|
See `backend/.env.example` for all available options including `DATABASE_URL`, Ivanti API, Jira, Atlas, CARD, and GitLab integration keys.
|
||||||
|
|
||||||
### Start PostgreSQL
|
### Start PostgreSQL
|
||||||
|
|
||||||
@@ -47,6 +85,14 @@ chmod +x scripts/deploy-postgres.sh
|
|||||||
|
|
||||||
For fresh installs without an existing SQLite database, the script creates the schema and skips migration.
|
For fresh installs without an existing SQLite database, the script creates the schema and skips migration.
|
||||||
|
|
||||||
|
### Run Migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend && node migrations/run-all.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Migrations are idempotent and safe to re-run.
|
||||||
|
|
||||||
### Build and Run
|
### Build and Run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -57,80 +103,801 @@ cd frontend && npm run build && cd ..
|
|||||||
./start-servers.sh
|
./start-servers.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Dashboard: http://localhost:3000 · API: http://localhost:3001
|
Dashboard: http://localhost:3001
|
||||||
|
|
||||||
The helper scripts use `systemctl` under the hood — the systemd units in `systemd/` must be installed first. See the full manual for setup instructions.
|
The helper scripts use `systemctl` under the hood — the systemd units in `systemd/` must be installed first. See the full reference manual for setup instructions.
|
||||||
|
|
||||||
|
### Interactive Configuration Wizard
|
||||||
|
|
||||||
|
For first-time deployments, the wizard walks through all required settings:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node configure.js
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
| Feature | Description |
|
### Home — CVE Management
|
||||||
|---------|-------------|
|
|
||||||
| **CVE Management** | Track CVEs across multiple vendors with document storage and NVD auto-fill |
|
Searchable CVE list with per-vendor tracking and document storage. NVD API integration auto-populates severity, description, and publication date from the National Vulnerability Database.
|
||||||
| **Reporting** | Ivanti host finding triage with donut charts, inline editing, advanced filtering, CSV/XLSX export |
|
|
||||||
| **Ivanti Queue** | Personal staging list for batch FP, Archer, CARD, and Granite workflows |
|
**Capabilities:**
|
||||||
| **FP Workflow** | Submit false positive workflows directly to Ivanti API with attachments |
|
- Create, edit, and delete CVE entries with vendor association
|
||||||
| **Compliance** | Weekly AEO xlsx upload with diff preview, drift detection, per-team metric health cards |
|
- Upload advisory documents (PDF, email, screenshot, patch notes) per CVE/vendor pair
|
||||||
| **Archive Tracking** | Automatic detection of disappeared/returned findings with BU reassignment classification |
|
- NVD auto-lookup on CVE ID entry (rate-limited, API key optional for higher throughput)
|
||||||
| **Findings Trend** | Historical open vs closed chart with archive activity sparkline and shift reason tooltips |
|
- Filter by vendor, severity, status, and free-text search
|
||||||
| **Jira Integration** | Create, sync, and track Jira Data Center tickets linked to CVE/vendor pairs |
|
- Required document tracking per vendor with mandatory/optional flags
|
||||||
| **Archer Tickets** | Track risk acceptance exceptions (EXC numbers) linked to findings |
|
- Calendar widget with SLA date highlighting
|
||||||
| **CARD API** | Granite/CARD asset lookup integration for network device workflows |
|
|
||||||
| **Knowledge Base** | Internal document library with inline PDF/Markdown viewing |
|
### Reporting — Ivanti Host Findings
|
||||||
| **Access Control** | Four user groups (Admin, Standard_User, Leadership, Read_Only) with full audit trail |
|
|
||||||
|
Ivanti/RiskSense host finding triage with donut charts, advanced filtering, inline editing, CSV/XLSX export, and multi-BU scope.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Sync open host findings from Ivanti API (24-hour cadence, configurable via `IVANTI_BU_FILTER`)
|
||||||
|
- Group by Host toggle — collapses duplicate assets (same hostname + IP) with multiple findings into expandable rows
|
||||||
|
- CARD ownership tooltip on IP hover — displays confirmed/unconfirmed/candidate teams from CARD API
|
||||||
|
- CARD direct action modal — confirm, decline, or redirect ownership without a queue item
|
||||||
|
- Advanced column filtering, severity sorting, and free-text search
|
||||||
|
- Inline note editing with override hostname/DNS fields
|
||||||
|
- Per-user Ivanti identity for filtered FP workflow views
|
||||||
|
- Multi-select BU picker for scoping visible findings
|
||||||
|
- CSV and XLSX export with current filter state
|
||||||
|
- Add findings to the todo queue for batch workflow processing
|
||||||
|
|
||||||
|
### Ivanti Queue — Workflow Staging
|
||||||
|
|
||||||
|
Personal staging list for batch-processing FP, Archer, CARD, GRANITE, DECOM, and Remediate workflows.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Add individual findings or bulk-select from the Reporting page
|
||||||
|
- Six workflow types: FP (False Positive), Archer (Risk Acceptance), CARD (Ownership), GRANITE (Loader Sheet), DECOM (Decommission), Remediate
|
||||||
|
- Collapsible sections per workflow type
|
||||||
|
- Multi-item Jira ticket creation (consolidation modal)
|
||||||
|
- Ticket link display on completed items
|
||||||
|
- Clear Completed with FK-safe deletion
|
||||||
|
- Redirect pending items between workflow types without duplication
|
||||||
|
- DECOM items auto-note and auto-hide the finding on completion
|
||||||
|
|
||||||
|
### FP Workflow Submission
|
||||||
|
|
||||||
|
Submit False Positive workflows directly to the Ivanti API with attachments and lifecycle tracking.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Batch-select queue items for FP submission
|
||||||
|
- Attach supporting documents (10MB limit per file)
|
||||||
|
- Configurable expiration date, scope override, and reason
|
||||||
|
- Lifecycle tracking: submitted, approved, rejected, rework, resubmitted
|
||||||
|
- Edit and re-submit rejected workflows
|
||||||
|
- Re-queue findings from rejected submissions
|
||||||
|
- Auto-clear approved submissions, dismiss rejected
|
||||||
|
- Per-user workflow history with attachment results
|
||||||
|
- Collapsible submissions panel
|
||||||
|
|
||||||
|
### Archer Tickets
|
||||||
|
|
||||||
|
Track Archer risk acceptance exceptions (EXC numbers) linked to CVE/vendor pairs.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Create Archer ticket records with EXC number, URL, and status
|
||||||
|
- Status workflow: Draft, Open, Under Review, Accepted
|
||||||
|
- Link tickets to specific CVE/vendor combinations
|
||||||
|
- Full CRUD with audit logging
|
||||||
|
|
||||||
|
### Archer Template Library
|
||||||
|
|
||||||
|
Template management system for Archer Risk Acceptance forms. Stores static content (Environment Overview, Segmentation, Mitigating Controls) organised by Vendor, Platform, and Model.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Full CRUD with clone, search/filter, and per-section copy-to-clipboard
|
||||||
|
- Inline view panel with per-section copy buttons
|
||||||
|
- Template selector integrated into the Ivanti Queue for Archer workflow items
|
||||||
|
- Organised hierarchy: Vendor > Platform > Model
|
||||||
|
- Accessible from nav drawer (Template Mgr) and Ivanti Queue Archer items
|
||||||
|
|
||||||
|
### AEO Compliance
|
||||||
|
|
||||||
|
Weekly AEO compliance xlsx upload with diff preview, drift detection, per-team metric health cards, and device-level violation tracking.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Upload weekly compliance spreadsheets (xlsx) with automated parsing
|
||||||
|
- Diff preview showing new, resolved, and recurring non-compliant items
|
||||||
|
- Per-team metric health cards with pass/fail indicators
|
||||||
|
- Device-level violation detail panel with notes per hostname/metric pair
|
||||||
|
- Bulk notes import from CSV
|
||||||
|
- Compliance history tracking across uploads
|
||||||
|
- Per-metric estimated resolution date display
|
||||||
|
- Notes with group_id for batch operations
|
||||||
|
|
||||||
|
### CCP Metrics — Multi-Vertical Compliance
|
||||||
|
|
||||||
|
Cross-organisational VCL (Vulnerability Compliance Level) upload and reporting for multiple verticals. The CCP Metrics page provides executive-level visibility into compliance posture across teams.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Multi-vertical VCL xlsx upload with Summary and Detail sheet parsing
|
||||||
|
- Metric-first hierarchy with per-metric remediation plans
|
||||||
|
- Per-metric forecast burndown chart
|
||||||
|
- Aggregated burndown forecast on overview page
|
||||||
|
- Sub-team drill-down with intermediate view and per-team breakdowns
|
||||||
|
- Non-Compliant stat clickable with metric breakdown buttons
|
||||||
|
- Compliant/total counts on metric summary cards
|
||||||
|
- LIVE and LAST REPORT badges showing data freshness
|
||||||
|
- Data management panel — delete vertical, rollback upload, reset all
|
||||||
|
- Exec report page with exportable summaries
|
||||||
|
- Inline-editable team fields on vertical metadata
|
||||||
|
- Device metadata fields for asset context
|
||||||
|
|
||||||
|
### CARD Asset Ownership
|
||||||
|
|
||||||
|
CARD API integration for asset ownership management — confirm, decline, and redirect ownership for network assets.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Owner lookup by IP address or Ivanti Host ID (asset-search)
|
||||||
|
- Confirm, decline, and redirect ownership actions via API
|
||||||
|
- Suffix-guessing fallback when no host_id available (CTEC, NATL, CHTR, COML, RESI, WIFI, VOIP)
|
||||||
|
- IP address validation before mutation operations
|
||||||
|
- Update_token handling for safe concurrent operations
|
||||||
|
- Cached tooltip results per session
|
||||||
|
- Team assets endpoint for batch enrichment
|
||||||
|
- Quick mode (CTEC suffix only, 15s timeout) for tooltip performance
|
||||||
|
|
||||||
|
### Granite Loader Sheet
|
||||||
|
|
||||||
|
Generate Granite Loader Sheets with CARD enrichment, searchable picklists, per-row editing, and XLSX export.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Generate loader sheets from queue items or the Reporting page
|
||||||
|
- CARD enrichment — pull NCIM, Qualys, Netops Granite data per asset
|
||||||
|
- Searchable picklists for teams, statuses, operation types
|
||||||
|
- Per-row inline editing before export
|
||||||
|
- Column groups with configurable visibility
|
||||||
|
- XLSX export with formatting
|
||||||
|
|
||||||
|
### Atlas Action Plans
|
||||||
|
|
||||||
|
Atlas InfoSec action plan tracking with per-host vulnerability mapping and local cache for badge rendering.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- View action plans linked to Ivanti host findings via host_id
|
||||||
|
- Create remediation, risk acceptance, and compensating control plans
|
||||||
|
- AtlasBadge component on findings rows indicating plan existence
|
||||||
|
- Slide-out detail panel with plan metadata
|
||||||
|
- Local cache (`atlas_action_plans_cache` table) for instant badge rendering
|
||||||
|
- Manual cache refresh triggers re-fetch from Atlas API
|
||||||
|
- Qualys vulnerability mapping per host
|
||||||
|
|
||||||
|
### Jira Integration
|
||||||
|
|
||||||
|
Create, sync, and track Jira Data Center tickets linked to CVE/vendor pairs and Ivanti queue items.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Create tickets from CVE records or Ivanti queue items
|
||||||
|
- Multi-item Jira ticket creation from the consolidation modal
|
||||||
|
- Flexible ticket creation — CVE/Vendor fields optional, source context tracking
|
||||||
|
- Vendor-specific issue type dropdown with per-vendor project keys
|
||||||
|
- JQL-based ticket lookup and sync
|
||||||
|
- Raw Jira status display (no status mapping)
|
||||||
|
- Save to Dashboard from Jira lookup results
|
||||||
|
- Dedicated Jira page for managing tickets
|
||||||
|
- Rate limiting with configurable window and burst limits
|
||||||
|
- Blocked dangerous endpoints (bulk delete, user management)
|
||||||
|
|
||||||
|
### Finding Archive Tracking
|
||||||
|
|
||||||
|
Automatic detection of disappeared and returned findings with BU reassignment classification and anomaly logging.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Detect findings that disappear between syncs — classify as ARCHIVED, RETURNED, CLOSED, or CLOSED_GONE
|
||||||
|
- BU reassignment tracking with history log
|
||||||
|
- Sync anomaly detection with significance thresholds
|
||||||
|
- Anomaly banner component on the Reporting page
|
||||||
|
- Archive summary bar with state distribution
|
||||||
|
- Transition history with severity-at-transition recording
|
||||||
|
- Return classification (original finding restored vs. new duplicate)
|
||||||
|
- Configurable `IVANTI_MANAGED_BUS` for drift classification scope
|
||||||
|
|
||||||
|
### Findings Trend
|
||||||
|
|
||||||
|
Historical open vs closed findings chart with per-BU trend lines, archive activity sparkline, and shift reason tooltips.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Ivanti counts history chart (open/closed over time)
|
||||||
|
- Per-BU trend lines via `ivanti_counts_history_by_bu`
|
||||||
|
- Archive activity sparkline overlay
|
||||||
|
- Shift reason tooltips from anomaly log
|
||||||
|
|
||||||
|
### Knowledge Base
|
||||||
|
|
||||||
|
Internal document library for policies, guides, and reference material.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Upload documents (PDF, Markdown, Word, Excel)
|
||||||
|
- Inline PDF and Markdown viewing
|
||||||
|
- Category-based organisation with search
|
||||||
|
- Slug-based URL routing
|
||||||
|
|
||||||
|
### Exports
|
||||||
|
|
||||||
|
Dedicated Exports page with pre-built export cards for common data pulls.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Jira Tickets export
|
||||||
|
- CCP Metrics export
|
||||||
|
- Remediation Status export
|
||||||
|
- CSV and XLSX format options
|
||||||
|
|
||||||
|
### In-App Notifications
|
||||||
|
|
||||||
|
Native notification system replacing the previous Webex bot integration.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Per-user notification bell with unread count
|
||||||
|
- Notification types for sync events, workflow completions, and system alerts
|
||||||
|
- Mark as read / dismiss actions
|
||||||
|
- Persistent storage in `notifications` table
|
||||||
|
|
||||||
|
### Feedback — GitLab Integration
|
||||||
|
|
||||||
|
In-app bug reports and feature requests submitted directly to the GitLab project as issues.
|
||||||
|
|
||||||
|
**Capabilities:**
|
||||||
|
- Feedback modal accessible from the nav drawer
|
||||||
|
- Bug report and feature request templates
|
||||||
|
- Submitted as GitLab issues via PAT authentication
|
||||||
|
- GitLab webhook receiver for issue lifecycle events (label changes, closes)
|
||||||
|
- Webhook secret validation for security
|
||||||
|
|
||||||
|
### Access Control
|
||||||
|
|
||||||
|
Four user groups with role-based permissions and full audit trail.
|
||||||
|
|
||||||
|
| Group | Permissions |
|
||||||
|
|-------|------------|
|
||||||
|
| Admin | Full CRUD, user management, audit log access, system configuration, data management |
|
||||||
|
| Standard_User | Create/update operations, FP workflow submission, queue management |
|
||||||
|
| Leadership | Read access to all data plus compliance and export views |
|
||||||
|
| Read_Only | Read-only access to all data |
|
||||||
|
|
||||||
|
**Additional capabilities:**
|
||||||
|
- Per-user BU team assignments (multi-BU tenancy)
|
||||||
|
- Per-user Ivanti identity (first/last name) for workflow filtering
|
||||||
|
- Cookie-based sessions with 24-hour expiry (httpOnly)
|
||||||
|
- Login rate limiting (20 attempts per 15-minute window)
|
||||||
|
- Full audit trail for all state-changing operations
|
||||||
|
- User profile panel with password change
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
cve-dashboard/
|
cve-dashboard/
|
||||||
├── backend/
|
├── backend/
|
||||||
│ ├── server.js # Express API server
|
│ ├── server.js # Express API — middleware, CVE/document routes inline
|
||||||
│ ├── db.js # PostgreSQL connection pool (pg)
|
│ ├── db.js # PostgreSQL connection pool (pg)
|
||||||
│ ├── db-schema.sql # Complete DDL for fresh Postgres setup
|
│ ├── db-schema.sql # Complete DDL for fresh Postgres setup
|
||||||
│ ├── setup-postgres.js # Schema initializer (runs db-schema.sql)
|
│ ├── setup.js # One-time DB init + default admin creation
|
||||||
│ ├── routes/ # API route handlers
|
│ ├── routes/
|
||||||
│ ├── helpers/ # API clients (Ivanti, Jira, Atlas, CARD)
|
│ │ ├── auth.js # Login, logout, session validation
|
||||||
│ ├── middleware/ # Auth middleware
|
│ │ ├── users.js # User CRUD, role/group management
|
||||||
│ ├── migrations/ # Schema migrations (legacy SQLite deployments)
|
│ │ ├── auditLog.js # Audit log queries
|
||||||
│ └── scripts/ # Compliance parser, data import utilities
|
│ │ ├── nvdLookup.js # NVD API proxy
|
||||||
|
│ │ ├── knowledgeBase.js # Document library CRUD
|
||||||
|
│ │ ├── archerTickets.js # Archer EXC ticket tracking
|
||||||
|
│ │ ├── archerTemplates.js # Archer template library CRUD + clone
|
||||||
|
│ │ ├── ivantiWorkflows.js # Ivanti FP workflow batch queries
|
||||||
|
│ │ ├── ivantiFindings.js # Ivanti findings sync, query, inline edit
|
||||||
|
│ │ ├── ivantiTodoQueue.js # Per-user queue staging
|
||||||
|
│ │ ├── ivantiArchive.js # Finding archive tracking + anomaly log
|
||||||
|
│ │ ├── ivantiFpWorkflow.js# FP workflow submission to Ivanti API
|
||||||
|
│ │ ├── compliance.js # AEO compliance upload + items + notes
|
||||||
|
│ │ ├── vclMultiVertical.js# VCL/CCP multi-vertical compliance
|
||||||
|
│ │ ├── atlas.js # Atlas action plan proxy + cache
|
||||||
|
│ │ ├── jiraTickets.js # Jira CRUD + REST API integration
|
||||||
|
│ │ ├── cardApi.js # CARD ownership proxy + asset-search
|
||||||
|
│ │ ├── notifications.js # In-app notification system
|
||||||
|
│ │ ├── feedback.js # GitLab issue creation for bug/feature
|
||||||
|
│ │ └── webhooks.js # GitLab webhook receiver
|
||||||
|
│ ├── helpers/
|
||||||
|
│ │ ├── auditLog.js # logAudit() — fire-and-forget DB insert
|
||||||
|
│ │ ├── cardApi.js # CARD API — OAuth token, owner lookup, asset-search
|
||||||
|
│ │ ├── ivantiApi.js # Ivanti/RiskSense HTTP helpers
|
||||||
|
│ │ ├── atlasApi.js # Atlas action plan API
|
||||||
|
│ │ ├── jiraApi.js # Jira ticket creation + rate limiter
|
||||||
|
│ │ ├── driftChecker.js # BU drift detection between syncs
|
||||||
|
│ │ ├── vclHelpers.js # VCL metric calculation helpers
|
||||||
|
│ │ └── teams.js # Team validation helpers
|
||||||
|
│ ├── middleware/
|
||||||
|
│ │ └── auth.js # requireAuth(), requireGroup(...groups)
|
||||||
|
│ ├── migrations/ # Sequential migration scripts (idempotent)
|
||||||
|
│ │ └── run-all.js # Run all migrations in order
|
||||||
|
│ └── scripts/ # Python utilities (compliance parsing)
|
||||||
|
│
|
||||||
├── frontend/
|
├── frontend/
|
||||||
│ ├── src/
|
│ └── src/
|
||||||
│ │ ├── App.js # Main app with routing
|
│ ├── App.js # Main app — routing, CVE list, filters, modals
|
||||||
│ │ ├── components/ # React components
|
│ ├── App.css # Global styles and CSS variables
|
||||||
│ │ └── contexts/ # Auth context
|
│ ├── contexts/
|
||||||
│ └── public/
|
│ │ └── AuthContext.js # Auth state provider (login, logout, role helpers)
|
||||||
|
│ ├── utils/
|
||||||
|
│ │ ├── graniteLoaderConfig.js # Granite column definitions and groups
|
||||||
|
│ │ ├── graniteLoaderExport.js # XLSX generation logic
|
||||||
|
│ │ └── graniteLoaderPicklists.js # Searchable dropdown options
|
||||||
|
│ └── components/
|
||||||
|
│ ├── LoginForm.js
|
||||||
|
│ ├── NavDrawer.js
|
||||||
|
│ ├── UserMenu.js
|
||||||
|
│ ├── UserProfilePanel.js
|
||||||
|
│ ├── CalendarWidget.js
|
||||||
|
│ ├── UserManagement.js
|
||||||
|
│ ├── AuditLog.js
|
||||||
|
│ ├── NvdSyncModal.js
|
||||||
|
│ ├── KnowledgeBaseModal.js
|
||||||
|
│ ├── KnowledgeBaseViewer.js
|
||||||
|
│ ├── CardOwnerTooltip.js
|
||||||
|
│ ├── CardDetailModal.js
|
||||||
|
│ ├── CardActionModal.js
|
||||||
|
│ ├── RedirectModal.js
|
||||||
|
│ ├── LoaderModal.js
|
||||||
|
│ ├── SearchableSelect.js
|
||||||
|
│ ├── AtlasBadge.js
|
||||||
|
│ ├── AtlasIcon.js
|
||||||
|
│ ├── AtlasSlideOutPanel.js
|
||||||
|
│ ├── AdminScopeToggle.js
|
||||||
|
│ ├── ConfirmModal.js
|
||||||
|
│ ├── ConsolidationModal.js
|
||||||
|
│ ├── CveTooltip.js
|
||||||
|
│ ├── DeleteConfirmModal.js
|
||||||
|
│ ├── FeedbackModal.js
|
||||||
|
│ ├── NotificationBell.js
|
||||||
|
│ ├── RemediationModal.js
|
||||||
|
│ ├── TemplateFormModal.js
|
||||||
|
│ ├── TemplateSelector.js
|
||||||
|
│ └── pages/
|
||||||
|
│ ├── AdminPage.js
|
||||||
|
│ ├── ReportingPage.js
|
||||||
|
│ ├── IvantiTodoQueuePage.js
|
||||||
|
│ ├── CompliancePage.js
|
||||||
|
│ ├── ComplianceUploadModal.js
|
||||||
|
│ ├── ComplianceDetailPanel.js
|
||||||
|
│ ├── ComplianceChartsPanel.js
|
||||||
|
│ ├── CCPMetricsPage.js
|
||||||
|
│ ├── VCLReportPage.js
|
||||||
|
│ ├── MetricInfoPanel.js
|
||||||
|
│ ├── BulkUploadModal.js
|
||||||
|
│ ├── MultiVerticalUploadModal.js
|
||||||
|
│ ├── IvantiCountsChart.js
|
||||||
|
│ ├── AnomalyBanner.js
|
||||||
|
│ ├── ArchiveSummaryBar.js
|
||||||
|
│ ├── ArcherPage.js
|
||||||
|
│ ├── ArcherTemplatePage.js
|
||||||
|
│ ├── JiraPage.js
|
||||||
|
│ ├── KnowledgeBasePage.js
|
||||||
|
│ └── ExportsPage.js
|
||||||
|
│
|
||||||
├── docs/
|
├── docs/
|
||||||
│ ├── api/ # API specs (Ivanti, Atlas, Jira)
|
│ ├── api/ # API specs (Ivanti, Atlas, Jira)
|
||||||
│ ├── design/ # Design system, workflow diagrams
|
│ ├── architecture/ # Architecture proposals (AD/SAML, split)
|
||||||
│ ├── guides/ # User guides, full reference manual
|
│ ├── design/ # Design system, workflow colour codes
|
||||||
|
│ ├── guides/ # User guides, full reference manual, VCL calculations
|
||||||
|
│ ├── operations/ # Operational logs and connectivity tests
|
||||||
│ ├── security/ # Security audits and remediation plans
|
│ ├── security/ # Security audits and remediation plans
|
||||||
│ ├── testing/ # Test plans and scripts
|
│ ├── testing/ # Test plans and scripts
|
||||||
│ └── troubleshooting/ # Investigation scripts and reports
|
│ └── troubleshooting/ # Investigation scripts and reports
|
||||||
├── docker-compose.yml # PostgreSQL 16 container definition
|
│
|
||||||
├── scripts/
|
├── scripts/
|
||||||
│ └── deploy-postgres.sh # One-time deployment: container, schema, migration
|
│ ├── deploy-postgres.sh # One-time: container, schema, migration
|
||||||
├── systemd/ # systemd service files
|
│ └── reset-and-migrate.sh # Dev utility: reset DB and re-run migrations
|
||||||
├── start-servers.sh
|
├── deploy/
|
||||||
└── stop-servers.sh
|
│ ├── cve-backend-production.service
|
||||||
|
│ ├── cve-backend-staging.service
|
||||||
|
│ └── setup-staging.sh
|
||||||
|
├── systemd/
|
||||||
|
│ ├── cve-backend.service
|
||||||
|
│ └── cve-frontend.service
|
||||||
|
├── configure.js # Interactive configuration wizard
|
||||||
|
├── docker-compose.yml # PostgreSQL 16 container definition
|
||||||
|
├── start-servers.sh # Start backend (serves API + frontend build)
|
||||||
|
├── stop-servers.sh # Stop backend
|
||||||
|
└── CHANGELOG.md
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
| Layer | Technology |
|
| Layer | Technology |
|
||||||
|-------|------------|
|
|-------|------------|
|
||||||
| Backend | Node.js 18+, Express 5 |
|
| Backend | Node.js 18+, Express 5 |
|
||||||
| Database | PostgreSQL 16 (Docker, port 5433) |
|
| Database | PostgreSQL 16 (Docker, port 5433) |
|
||||||
| Frontend | React 19, Recharts, Lucide React |
|
| Auth | bcryptjs, cookie-based sessions (httpOnly, 24h expiry), express-rate-limit |
|
||||||
| Auth | bcryptjs, cookie-based sessions, express-rate-limit |
|
| File uploads | Multer 2 (10MB limit) |
|
||||||
| Compliance | Python 3, pandas, openpyxl |
|
| Frontend | React 19 (Create React App / react-scripts 5) |
|
||||||
|
| Frontend serving | Express serves `frontend/build/` as static files on port 3001 |
|
||||||
|
| UI Icons | lucide-react |
|
||||||
|
| Charts | recharts |
|
||||||
|
| Spreadsheet parsing | xlsx (frontend), pandas + openpyxl (backend Python scripts) |
|
||||||
|
| Markdown rendering | react-markdown + rehype-sanitize |
|
||||||
|
| Diagrams | mermaid |
|
||||||
|
| Testing | Jest 30 (backend property tests), React Testing Library (frontend) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
All configuration lives in `backend/.env`. Copy `backend/.env.example` as a starting point.
|
||||||
|
|
||||||
|
| Variable | Purpose | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `PORT` | Backend server port | `3001` |
|
||||||
|
| `API_HOST` | Backend bind address | `localhost` |
|
||||||
|
| `CORS_ORIGINS` | Comma-separated allowed origins | `http://localhost:3000` |
|
||||||
|
| `SESSION_SECRET` | **Required.** Session signing key. Generate with `openssl rand -base64 32` | — |
|
||||||
|
| `DATABASE_URL` | PostgreSQL connection string | — |
|
||||||
|
| `NVD_API_KEY` | NVD API key (increases rate limit from 5 to 50 req/30s) | — |
|
||||||
|
| `IVANTI_API_KEY` | Ivanti/RiskSense API key | — |
|
||||||
|
| `IVANTI_CLIENT_ID` | Ivanti client ID | `1550` |
|
||||||
|
| `IVANTI_FIRST_NAME` | Fallback Ivanti identity (first name) | — |
|
||||||
|
| `IVANTI_LAST_NAME` | Fallback Ivanti identity (last name) | — |
|
||||||
|
| `IVANTI_BU_FILTER` | Comma-separated BU values to sync | `NTS-AEO-ACCESS-ENG,NTS-AEO-STEAM` |
|
||||||
|
| `IVANTI_MANAGED_BUS` | BUs considered "managed" for drift classification | `NTS-AEO-ACCESS-ENG,NTS-AEO-STEAM` |
|
||||||
|
| `IVANTI_SKIP_TLS` | Skip TLS verification for SSL inspection proxies | `false` |
|
||||||
|
| `ATLAS_API_URL` | Atlas InfoSec API base URL | — |
|
||||||
|
| `ATLAS_API_USER` | Atlas Basic Auth username | — |
|
||||||
|
| `ATLAS_API_PASS` | Atlas Basic Auth password | — |
|
||||||
|
| `ATLAS_SKIP_TLS` | Skip Atlas TLS verification | `false` |
|
||||||
|
| `JIRA_BASE_URL` | Jira Data Center REST API base URL | — |
|
||||||
|
| `JIRA_AUTH_METHOD` | Auth method: `basic` or `pat` | `basic` |
|
||||||
|
| `JIRA_API_USER` | Jira Basic Auth username | — |
|
||||||
|
| `JIRA_API_TOKEN` | Jira Basic Auth token | — |
|
||||||
|
| `JIRA_PAT` | Jira Personal Access Token (when `JIRA_AUTH_METHOD=pat`) | — |
|
||||||
|
| `JIRA_PROJECT_KEY` | Default Jira project key | — |
|
||||||
|
| `JIRA_ISSUE_TYPE` | Default issue type | `Task` |
|
||||||
|
| `JIRA_SKIP_TLS` | Skip Jira TLS verification | `false` |
|
||||||
|
| `CARD_API_URL` | CARD API base URL | — |
|
||||||
|
| `CARD_API_USER` | CARD OAuth username | — |
|
||||||
|
| `CARD_API_PASS` | CARD OAuth password | — |
|
||||||
|
| `CARD_SKIP_TLS` | Skip CARD TLS verification | `false` |
|
||||||
|
| `GITLAB_URL` | GitLab instance URL for feedback integration | `http://steam-gitlab.charterlab.com` |
|
||||||
|
| `GITLAB_PROJECT_ID` | GitLab project numeric ID | — |
|
||||||
|
| `GITLAB_PAT` | GitLab project access token (api scope) | — |
|
||||||
|
| `GITLAB_WEBHOOK_SECRET` | Shared secret for webhook validation | — |
|
||||||
|
|
||||||
|
> `SESSION_SECRET` and `DATABASE_URL` are required for the backend to start. All integration keys are optional — features degrade gracefully when their keys are absent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database Schema
|
||||||
|
|
||||||
|
PostgreSQL 16 with the following tables:
|
||||||
|
|
||||||
|
| Table | Purpose |
|
||||||
|
|-------|---------|
|
||||||
|
| `cves` | CVE records with vendor association, severity, status |
|
||||||
|
| `documents` | Uploaded advisory documents linked to CVE/vendor pairs |
|
||||||
|
| `required_documents` | Per-vendor required document types |
|
||||||
|
| `users` | User accounts with role, group, BU teams, Ivanti identity |
|
||||||
|
| `sessions` | Active session tokens with expiry |
|
||||||
|
| `audit_logs` | Immutable audit trail for all state-changing operations |
|
||||||
|
| `jira_tickets` | Locally tracked Jira tickets linked to CVE/vendor |
|
||||||
|
| `archer_tickets` | Archer risk acceptance exceptions (EXC numbers) |
|
||||||
|
| `knowledge_base` | Internal document library entries |
|
||||||
|
| `ivanti_findings` | Individual Ivanti host findings (synced from API) |
|
||||||
|
| `ivanti_sync_state` | Sync metadata — last run time, status, error |
|
||||||
|
| `ivanti_counts_cache` | Cached open/closed counts and FP workflow counts |
|
||||||
|
| `ivanti_counts_history` | Historical open/closed counts over time |
|
||||||
|
| `ivanti_counts_history_by_bu` | Per-BU historical counts |
|
||||||
|
| `ivanti_fp_submissions` | FP workflow submissions with lifecycle tracking |
|
||||||
|
| `ivanti_fp_submission_history` | Edit history for FP submissions |
|
||||||
|
| `ivanti_todo_queue` | Per-user workflow staging queue |
|
||||||
|
| `ivanti_finding_archives` | Archived/returned/closed finding records |
|
||||||
|
| `ivanti_archive_transitions` | State transition history for archived findings |
|
||||||
|
| `ivanti_sync_anomaly_log` | Sync anomaly detection log |
|
||||||
|
| `ivanti_finding_bu_history` | BU reassignment history per finding |
|
||||||
|
| `atlas_action_plans_cache` | Cached Atlas action plan data for badge rendering |
|
||||||
|
| `compliance_uploads` | Compliance xlsx upload metadata |
|
||||||
|
| `compliance_items` | Individual non-compliant items per upload |
|
||||||
|
| `compliance_notes` | Per-hostname/metric notes |
|
||||||
|
|
||||||
|
The complete DDL is in `backend/db-schema.sql`. For fresh installs, `scripts/deploy-postgres.sh` applies it automatically.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migrations
|
||||||
|
|
||||||
|
Run all migrations (idempotent):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend && node migrations/run-all.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Migration files in execution order:
|
||||||
|
|
||||||
|
| Migration | Purpose |
|
||||||
|
|-----------|---------|
|
||||||
|
| `add_user_groups.js` | User group column and check constraint |
|
||||||
|
| `add_user_ivanti_identity.js` | Per-user Ivanti first/last name |
|
||||||
|
| `add_user_bu_teams.js` | Per-user BU team assignments |
|
||||||
|
| `add_knowledge_base_table.js` | Knowledge base document library |
|
||||||
|
| `add_ivanti_sync_table.js` | Ivanti sync state (single-row) |
|
||||||
|
| `add_ivanti_findings_tables.js` | Individual findings + counts cache |
|
||||||
|
| `add_ivanti_findings_ipv6_columns.js` | IPv6 fallback columns |
|
||||||
|
| `add_ivanti_counts_history_table.js` | Historical counts + per-BU |
|
||||||
|
| `add_ivanti_todo_queue_table.js` | Per-user workflow staging queue |
|
||||||
|
| `add_todo_queue_hostname.js` | Hostname column on queue items |
|
||||||
|
| `add_todo_queue_ip_address.js` | IP address column on queue items |
|
||||||
|
| `add_granite_workflow_type.js` | GRANITE workflow type |
|
||||||
|
| `add_card_workflow_type.js` | CARD workflow type |
|
||||||
|
| `add_decom_workflow_type.js` | DECOM workflow type |
|
||||||
|
| `add_remediate_workflow_type.js` | Remediate workflow type |
|
||||||
|
| `add_compliance_tables.js` | Compliance uploads, items, notes |
|
||||||
|
| `add_compliance_notes_group_id.js` | Group ID for batch notes |
|
||||||
|
| `add_compliance_history_metric_id.js` | Metric ID in compliance history |
|
||||||
|
| `add_compliance_item_history.js` | Compliance item history tracking |
|
||||||
|
| `add_fp_submissions_table.js` | FP workflow submissions |
|
||||||
|
| `add_fp_submission_editing.js` | Submission edit history |
|
||||||
|
| `add_fp_submissions_dismissed.js` | Dismissed/lifecycle status |
|
||||||
|
| `add_fp_submissions_requeued_at.js` | Requeue timestamp |
|
||||||
|
| `add_archer_tickets_table.js` | Archer EXC tickets |
|
||||||
|
| `add_archer_tickets_timestamps.js` | Timestamp columns |
|
||||||
|
| `add_archer_templates_table.js` | Archer template library |
|
||||||
|
| `add_atlas_action_plans_cache.js` | Atlas plan cache |
|
||||||
|
| `add_atlas_known_column.js` | Atlas known flag |
|
||||||
|
| `add_finding_archive_tables.js` | Archive tracking tables |
|
||||||
|
| `add_closed_gone_state.js` | CLOSED_GONE archive state |
|
||||||
|
| `add_return_classification.js` | Return classification field |
|
||||||
|
| `add_sync_anomaly_tables.js` | Anomaly detection log |
|
||||||
|
| `add_flexible_jira_ticket_creation.js` | Optional CVE/vendor on Jira tickets |
|
||||||
|
| `add_multi_item_jira_ticket.js` | Multi-item ticket references |
|
||||||
|
| `add_jira_sync_columns.js` | Jira sync metadata (SQLite) |
|
||||||
|
| `add_jira_sync_columns_pg.js` | Jira sync metadata (PostgreSQL) |
|
||||||
|
| `drop_jira_status_check_constraint.js` | Remove status enum for raw display |
|
||||||
|
| `add_notifications_table.js` | In-app notification system |
|
||||||
|
| `add_created_by_columns.js` | created_by on archer_tickets |
|
||||||
|
| `add_queue_remediation_notes_table.js` | Remediation notes on queue items |
|
||||||
|
| `add_vcl_multi_vertical.js` | VCL multi-vertical tables |
|
||||||
|
| `add_vcl_reporting_columns.js` | VCL reporting metadata |
|
||||||
|
| `add_vcl_vertical_metadata.js` | VCL vertical team fields |
|
||||||
|
| `backfill_anomaly_log.js` | Backfill anomaly classification data |
|
||||||
|
| `backfill_return_classification.js` | Backfill return classification |
|
||||||
|
| `reclassify_bu_roundtrips.js` | Reclassify BU roundtrip transitions |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
All routes are prefixed with `/api`. All endpoints except login, logout, health check, and webhooks require a valid session cookie.
|
||||||
|
|
||||||
|
### Public
|
||||||
|
|
||||||
|
| Method | Path | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| GET | `/api/health` | Health check (used by CI/CD verification) |
|
||||||
|
| POST | `/api/auth/login` | Authenticate and create session |
|
||||||
|
| POST | `/api/auth/logout` | Destroy session |
|
||||||
|
| POST | `/api/webhooks/gitlab` | GitLab webhook receiver (validated by secret) |
|
||||||
|
|
||||||
|
### CVE Management
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/cves` | List CVEs with filtering | Any |
|
||||||
|
| POST | `/api/cves` | Create CVE | Standard_User+ |
|
||||||
|
| PUT | `/api/cves/:id` | Update CVE | Standard_User+ |
|
||||||
|
| DELETE | `/api/cves/:id` | Delete CVE | Admin |
|
||||||
|
| POST | `/api/cves/:cveId/:vendor/documents` | Upload document | Standard_User+ |
|
||||||
|
| GET | `/api/cves/:cveId/:vendor/documents` | List documents | Any |
|
||||||
|
| DELETE | `/api/documents/:id` | Delete document | Admin |
|
||||||
|
|
||||||
|
### Users and Auth
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/auth/me` | Current session user | Any |
|
||||||
|
| GET | `/api/users` | List all users | Admin |
|
||||||
|
| POST | `/api/users` | Create user | Admin |
|
||||||
|
| PUT | `/api/users/:id` | Update user (role, group, teams) | Admin |
|
||||||
|
| DELETE | `/api/users/:id` | Delete user | Admin |
|
||||||
|
| PUT | `/api/users/:id/password` | Change password | Owner or Admin |
|
||||||
|
|
||||||
|
### Ivanti Findings
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/ivanti/findings` | Query synced findings | Any |
|
||||||
|
| POST | `/api/ivanti/findings/sync` | Trigger manual sync | Standard_User+ |
|
||||||
|
| PUT | `/api/ivanti/findings/:id/note` | Update finding note | Standard_User+ |
|
||||||
|
| PUT | `/api/ivanti/findings/:id/override` | Override hostname/DNS | Standard_User+ |
|
||||||
|
|
||||||
|
### Ivanti Queue
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/ivanti/todo-queue` | Get user's queue | Any |
|
||||||
|
| POST | `/api/ivanti/todo-queue` | Add item(s) to queue | Standard_User+ |
|
||||||
|
| PUT | `/api/ivanti/todo-queue/:id` | Update queue item | Standard_User+ |
|
||||||
|
| DELETE | `/api/ivanti/todo-queue/:id` | Remove queue item | Standard_User+ |
|
||||||
|
| DELETE | `/api/ivanti/todo-queue/completed` | Clear completed items | Standard_User+ |
|
||||||
|
|
||||||
|
### Ivanti FP Workflow
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| POST | `/api/ivanti/fp-workflow` | Submit FP workflow to Ivanti | Standard_User+ |
|
||||||
|
| GET | `/api/ivanti/fp-workflow/submissions` | List user's submissions | Any |
|
||||||
|
| PUT | `/api/ivanti/fp-workflow/submissions/:id` | Edit/resubmit | Standard_User+ |
|
||||||
|
|
||||||
|
### Ivanti Archive
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/ivanti/archive` | Query archived findings | Any |
|
||||||
|
| GET | `/api/ivanti/archive/anomalies` | Sync anomaly log | Any |
|
||||||
|
| GET | `/api/ivanti/archive/transitions/:id` | Transition history | Any |
|
||||||
|
|
||||||
|
### Compliance (AEO)
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| POST | `/api/compliance/upload` | Upload xlsx | Standard_User+ |
|
||||||
|
| GET | `/api/compliance/items` | Query non-compliant items | Any |
|
||||||
|
| GET | `/api/compliance/trends` | Compliance trend data | Any |
|
||||||
|
| POST | `/api/compliance/notes` | Add note to hostname/metric | Standard_User+ |
|
||||||
|
|
||||||
|
### VCL Multi-Vertical (CCP Metrics)
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| POST | `/api/compliance/vcl-multi/upload` | Upload VCL xlsx | Standard_User+ |
|
||||||
|
| GET | `/api/compliance/vcl-multi/verticals` | List verticals | Any |
|
||||||
|
| GET | `/api/compliance/vcl-multi/metrics` | Query metrics | Any |
|
||||||
|
| GET | `/api/compliance/vcl-multi/forecast` | Burndown forecast | Any |
|
||||||
|
| DELETE | `/api/compliance/vcl-multi/verticals/:id` | Delete vertical | Admin |
|
||||||
|
|
||||||
|
### Atlas
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/atlas/hosts/:hostId/plans` | Get plans for host | Any |
|
||||||
|
| PUT | `/api/atlas/hosts/:hostId/plans` | Create plan | Standard_User+ |
|
||||||
|
| PATCH | `/api/atlas/hosts/:hostId/plans` | Update plan | Standard_User+ |
|
||||||
|
| POST | `/api/atlas/hosts/:hostId/refresh` | Refresh cache | Standard_User+ |
|
||||||
|
|
||||||
|
### Jira
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/jira-tickets` | List local tickets | Any |
|
||||||
|
| POST | `/api/jira-tickets` | Create ticket (local + Jira API) | Standard_User+ |
|
||||||
|
| GET | `/api/jira-tickets/lookup` | JQL search against Jira | Standard_User+ |
|
||||||
|
| POST | `/api/jira-tickets/save` | Save from Jira lookup | Standard_User+ |
|
||||||
|
|
||||||
|
### CARD
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/card/owner/:assetId` | Lookup owner | Any |
|
||||||
|
| GET | `/api/card/asset-search/:hostId` | Search by Ivanti host ID | Any |
|
||||||
|
| POST | `/api/card/owner/:assetId/confirm` | Confirm ownership | Standard_User+ |
|
||||||
|
| POST | `/api/card/owner/:assetId/decline` | Decline ownership | Standard_User+ |
|
||||||
|
| POST | `/api/card/owner/:assetId/redirect` | Redirect ownership | Standard_User+ |
|
||||||
|
| GET | `/api/card/teams` | List all CARD teams | Any |
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
| Method | Path | Description | Group |
|
||||||
|
|--------|------|-------------|-------|
|
||||||
|
| GET | `/api/audit-logs` | Query audit trail | Admin |
|
||||||
|
| GET | `/api/nvd/:cveId` | NVD metadata lookup | Any |
|
||||||
|
| GET/POST | `/api/knowledge-base` | Document library CRUD | Any / Standard_User+ |
|
||||||
|
| GET/POST | `/api/archer-tickets` | Archer ticket CRUD | Any / Standard_User+ |
|
||||||
|
| GET/POST | `/api/archer-templates` | Template library CRUD | Any / Standard_User+ |
|
||||||
|
| GET | `/api/notifications` | User notifications | Any |
|
||||||
|
| POST | `/api/feedback` | Submit bug/feature to GitLab | Any |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD Pipeline
|
||||||
|
|
||||||
|
Defined in `.gitlab-ci.yml`. Stages: install, lint, test, build, deploy, verify.
|
||||||
|
|
||||||
|
| Stage | What it does |
|
||||||
|
|-------|-------------|
|
||||||
|
| install | `npm ci` for root + frontend |
|
||||||
|
| lint | ESLint on frontend (warning threshold: 25) |
|
||||||
|
| test | Jest backend property tests + frontend unit tests |
|
||||||
|
| build | `npm run build` in frontend/ |
|
||||||
|
| deploy-staging | rsync to 71.85.90.9, run migrations, restart service (auto on master) |
|
||||||
|
| deploy-production | rsync to 71.85.90.6, run migrations, restart service (manual trigger) |
|
||||||
|
| verify | Hit `/api/health` endpoint, post issue comments for `Closes #N` references |
|
||||||
|
|
||||||
|
**Runner:** Docker executor on LXC 108 (71.85.90.8), Runner #6, `node:18` image for build stages, `alpine:latest` for deploy.
|
||||||
|
|
||||||
|
**Required CI/CD variables:** `DATABASE_URL`, `SSH_PRIVATE_KEY` (base64), `GITLAB_PAT`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- **[Full Reference Manual](docs/guides/full-reference-manual.md)** — comprehensive feature documentation, API reference, database schema, security model, and configuration details
|
- **[Full Reference Manual](docs/guides/full-reference-manual.md)** — comprehensive feature documentation, API reference, database schema, security model, and configuration details
|
||||||
|
- **[VCL Metric Calculations](docs/guides/vcl-metric-calculations.md)** — formula reference for CCP Metrics compliance calculations
|
||||||
- **[Postgres Migration Plan](docs/guides/postgres-migration-plan.md)** — architecture decisions, schema design, and cutover procedure for the SQLite to PostgreSQL migration
|
- **[Postgres Migration Plan](docs/guides/postgres-migration-plan.md)** — architecture decisions, schema design, and cutover procedure for the SQLite to PostgreSQL migration
|
||||||
- **[Migration Guide](backend/migrations/README.md)** — schema migration scripts for upgrading existing deployments
|
- **[Migration Guide](backend/migrations/README.md)** — schema migration scripts for upgrading existing deployments
|
||||||
- **[Design System](docs/design/design-system.md)** — UI component patterns and color system
|
- **[Design System](docs/design/design-system.md)** — UI component patterns and colour system
|
||||||
- **[Ivanti API Reference](docs/api/ivanti-api-reference.md)** — Ivanti/RiskSense API integration details
|
- **[Ivanti API Reference](docs/api/ivanti-api-reference.md)** — Ivanti/RiskSense API integration details
|
||||||
- **[Jira API Use Cases](docs/api/jira-api-use-cases.md)** — Jira Data Center API compliance summary
|
- **[Jira API Use Cases](docs/api/jira-api-use-cases.md)** — Jira Data Center API compliance summary
|
||||||
|
- **[AD/SAML Integration Architecture](docs/architecture/ad-saml-integration.md)** — planned Active Directory / SAML SSO integration
|
||||||
|
- **[Security Audit Tracker](docs/security/security-audit-tracker.md)** — living security audit document
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Backend fails to start with "FATAL: SESSION_SECRET"
|
||||||
|
|
||||||
|
**Symptom:** Server exits immediately with `FATAL: SESSION_SECRET environment variable must be set`.
|
||||||
|
|
||||||
|
**Cause:** The `SESSION_SECRET` env var is not configured in `backend/.env`.
|
||||||
|
|
||||||
|
**Fix:** Generate a secret and add it to `backend/.env`:
|
||||||
|
```bash
|
||||||
|
echo "SESSION_SECRET=$(openssl rand -base64 32)" >> backend/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database connection refused
|
||||||
|
|
||||||
|
**Symptom:** Backend logs `Error: connect ECONNREFUSED` on startup.
|
||||||
|
|
||||||
|
**Cause:** PostgreSQL container is not running or `DATABASE_URL` is misconfigured.
|
||||||
|
|
||||||
|
**Fix:**
|
||||||
|
```bash
|
||||||
|
docker compose up -d # Start the Postgres container
|
||||||
|
# Verify DATABASE_URL in backend/.env matches: postgresql://steam:<password>@localhost:5433/cve_dashboard
|
||||||
|
```
|
||||||
|
|
||||||
|
### CARD API timeouts in production
|
||||||
|
|
||||||
|
**Symptom:** CARD tooltip shows timeout errors or takes minutes to respond.
|
||||||
|
|
||||||
|
**Cause:** IPv6 AAAA records for `card.charter.com` are unreachable from this network. Node.js defaults to trying IPv6 first.
|
||||||
|
|
||||||
|
**Fix:** The backend sets `dns.setDefaultResultOrder('ipv4first')` globally. If you still see issues, verify the setting is at the top of `server.js` before any network imports.
|
||||||
|
|
||||||
|
### Compliance upload fails with "No items parsed"
|
||||||
|
|
||||||
|
**Symptom:** Upload completes but reports 0 new, 0 resolved, 0 recurring items.
|
||||||
|
|
||||||
|
**Cause:** The xlsx file structure does not match the expected format (sheet names, column headers).
|
||||||
|
|
||||||
|
**Fix:** Ensure the compliance xlsx has the expected sheet layout. Check `backend/scripts/parse_compliance_xlsx.py` for the expected column mappings.
|
||||||
|
|
||||||
|
### Missing migrations after deploy
|
||||||
|
|
||||||
|
**Symptom:** API returns 500 errors referencing missing columns or tables.
|
||||||
|
|
||||||
|
**Cause:** Migrations were not run after pulling new code.
|
||||||
|
|
||||||
|
**Fix:**
|
||||||
|
```bash
|
||||||
|
cd backend && node migrations/run-all.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend changes not visible after deploy
|
||||||
|
|
||||||
|
**Symptom:** UI still shows old version after code changes.
|
||||||
|
|
||||||
|
**Cause:** The frontend must be rebuilt after any source changes — Express serves the static build.
|
||||||
|
|
||||||
|
**Fix:**
|
||||||
|
```bash
|
||||||
|
cd frontend && npm run build
|
||||||
|
# Restart backend or refresh the browser
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user