docs: refresh README and add security posture workflow diagrams
- Rename project to STEAM Security Dashboard throughout README - Document Ivanti Queue feature (FP/Archer/CARD staging, per-user persistence) - Document AEO Compliance page (upload flow, metric health cards, device table, detail panel, View in Reporting link for 2.3.x metrics) - Add all missing migrations to install instructions (queue, CARD, ip_address, compliance tables) - Add Ivanti Queue and Compliance endpoint tables to API reference - Update architecture file tree with new routes, migrations, scripts, and frontend components - Add compliance DB tables to schema section - Document parse_compliance_xlsx.py in scripts section - Add security-posture-workflow-diagrams.md (Mermaid, VSCode/GitHub) - Add security-posture-workflow-lucidchart.md (Lucidchart import format)
This commit is contained in:
356
README.md
356
README.md
@@ -1,6 +1,6 @@
|
|||||||
# CVE Dashboard
|
# STEAM Security Dashboard
|
||||||
|
|
||||||
A self-hosted vulnerability management dashboard for tracking CVE remediation status, managing vendor documentation, monitoring Ivanti host findings, and overseeing False Positive (FP) workflows.
|
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 and Archer exception workflows, and internal documentation in a single interface.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -14,13 +14,16 @@ A self-hosted vulnerability management dashboard for tracking CVE remediation st
|
|||||||
- [Running the Application](#running-the-application)
|
- [Running the Application](#running-the-application)
|
||||||
- [Features](#features)
|
- [Features](#features)
|
||||||
- [Authentication and User Roles](#authentication-and-user-roles)
|
- [Authentication and User Roles](#authentication-and-user-roles)
|
||||||
- [Home Dashboard — CVE Management](#home-dashboard--cve-management)
|
- [Home — CVE Management](#home--cve-management)
|
||||||
- [Reporting — Host Findings](#reporting--host-findings)
|
- [Reporting — Host Findings](#reporting--host-findings)
|
||||||
|
- [Ivanti Queue](#ivanti-queue)
|
||||||
|
- [Compliance — AEO Posture](#compliance--aeo-posture)
|
||||||
- [Knowledge Base](#knowledge-base)
|
- [Knowledge Base](#knowledge-base)
|
||||||
|
- [Exports](#exports)
|
||||||
- [Archer Risk Acceptance Tickets](#archer-risk-acceptance-tickets)
|
- [Archer Risk Acceptance Tickets](#archer-risk-acceptance-tickets)
|
||||||
- [Weekly Reports](#weekly-reports)
|
- [Weekly Reports](#weekly-reports)
|
||||||
- [User Management](#user-management-admin)
|
- [User Management (Admin)](#user-management-admin)
|
||||||
- [Audit Log](#audit-log-admin)
|
- [Audit Log (Admin)](#audit-log-admin)
|
||||||
- [Scripts](#scripts)
|
- [Scripts](#scripts)
|
||||||
- [API Reference](#api-reference)
|
- [API Reference](#api-reference)
|
||||||
- [Architecture](#architecture)
|
- [Architecture](#architecture)
|
||||||
@@ -32,14 +35,16 @@ A self-hosted vulnerability management dashboard for tracking CVE remediation st
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The CVE Dashboard answers a common problem in vulnerability management: tracking which CVEs have been addressed, whether supporting vendor documentation exists, and where each finding is in the remediation or exception workflow.
|
The STEAM Security Dashboard answers a common problem in vulnerability management: tracking which CVEs have been addressed, whether supporting vendor documentation exists, where each finding is in the remediation or exception workflow, and how the team's overall AEO compliance posture is trending week over week.
|
||||||
|
|
||||||
The application provides:
|
The application provides:
|
||||||
|
|
||||||
- A searchable, filterable CVE list with per-vendor tracking and document storage
|
- A searchable, filterable CVE list with per-vendor tracking and document storage
|
||||||
- NVD API integration to auto-populate CVE metadata
|
- NVD API integration to auto-populate CVE metadata
|
||||||
- **Ivanti/RiskSense integration** to sync open and closed host findings with live FP workflow tracking
|
- **Ivanti/RiskSense integration** — sync open host findings with live FP workflow tracking
|
||||||
- **Reporting page** with donut charts, advanced per-column filtering, inline editing, and CSV/XLSX export
|
- **Reporting page** with donut charts, advanced per-column filtering, inline editing, Ivanti Queue, and CSV/XLSX export
|
||||||
|
- **Ivanti Queue** — personal staging list for batch-processing FP, Archer, and CARD workflows
|
||||||
|
- **AEO Compliance page** — weekly xlsx upload, diff preview, per-team metric health cards, device-level violation tracking with notes history
|
||||||
- Archer risk acceptance ticket tracking (EXC numbers) linked to CVE/vendor pairs
|
- Archer risk acceptance ticket tracking (EXC numbers) linked to CVE/vendor pairs
|
||||||
- Weekly vulnerability report upload and processing
|
- Weekly vulnerability report upload and processing
|
||||||
- A knowledge base for internal documentation and policies
|
- A knowledge base for internal documentation and policies
|
||||||
@@ -56,8 +61,8 @@ The application provides:
|
|||||||
| File uploads | Multer 2 |
|
| File uploads | Multer 2 |
|
||||||
| Auth | bcryptjs, cookie-based sessions |
|
| Auth | bcryptjs, cookie-based sessions |
|
||||||
| Frontend | React 19, lucide-react, xlsx |
|
| Frontend | React 19, lucide-react, xlsx |
|
||||||
| Report processing | Python 3 (stdlib only — no extra packages required for notes import) |
|
| Compliance / report processing | Python 3, pandas, openpyxl |
|
||||||
| Weekly report processing | Python 3, pandas, openpyxl |
|
| Bulk notes import | Python 3 (stdlib only) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -65,7 +70,7 @@ The application provides:
|
|||||||
|
|
||||||
- Node.js 18 or later
|
- Node.js 18 or later
|
||||||
- npm
|
- npm
|
||||||
- Python 3 (required for weekly report processing and bulk notes import)
|
- Python 3 with `pandas` and `openpyxl` (required for compliance xlsx parsing and weekly report processing)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -92,7 +97,7 @@ cd frontend
|
|||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Install Python dependencies (for weekly report processing)
|
### 4. Install Python dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend/scripts
|
cd backend/scripts
|
||||||
@@ -120,7 +125,7 @@ This creates `backend/cve_database.db` and a default admin account:
|
|||||||
|
|
||||||
### 6. Run database migrations
|
### 6. Run database migrations
|
||||||
|
|
||||||
After the initial setup, apply feature migrations in order:
|
Apply all feature migrations in order:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
@@ -129,9 +134,20 @@ node migrations/add_knowledge_base_table.js
|
|||||||
node migrations/add_archer_tickets_table.js
|
node migrations/add_archer_tickets_table.js
|
||||||
node migrations/add_ivanti_sync_table.js
|
node migrations/add_ivanti_sync_table.js
|
||||||
node migrations/add_ivanti_findings_tables.js
|
node migrations/add_ivanti_findings_tables.js
|
||||||
|
node migrations/add_ivanti_todo_queue_table.js
|
||||||
|
node migrations/add_card_workflow_type.js
|
||||||
|
node migrations/add_todo_queue_ip_address.js
|
||||||
|
node migrations/add_compliance_tables.js
|
||||||
```
|
```
|
||||||
|
|
||||||
The Ivanti findings tables migration also handles adding the `fp_workflow_counts_json` and `fp_id_counts_json` columns idempotently on each server start — no manual re-run is needed after the first run.
|
### 7. Build the frontend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use `npm start` for the development server (see [Running the Application](#running-the-application)).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -195,7 +211,7 @@ The start script saves PIDs to `backend.pid` and `frontend.pid`. Logs are writte
|
|||||||
cd backend
|
cd backend
|
||||||
node server.js
|
node server.js
|
||||||
|
|
||||||
# Terminal 2 — frontend
|
# Terminal 2 — frontend (development server)
|
||||||
cd frontend
|
cd frontend
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
@@ -217,17 +233,17 @@ All routes require authentication. Three roles are supported:
|
|||||||
|
|
||||||
| Role | Permissions |
|
| Role | Permissions |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `viewer` | Read-only: CVEs, documents, findings, reports, knowledge base, Archer tickets |
|
| `viewer` | Read-only: CVEs, documents, findings, reports, knowledge base, Archer tickets, compliance data |
|
||||||
| `editor` | All viewer permissions plus: create/update CVEs, upload documents, sync Ivanti findings, save notes and overrides, manage knowledge base articles, manage Archer tickets, upload weekly reports |
|
| `editor` | All viewer permissions plus: create/update CVEs, upload documents, sync Ivanti findings, save notes and overrides, manage knowledge base, manage Archer tickets, upload weekly reports, upload compliance reports, manage Ivanti Queue |
|
||||||
| `admin` | All editor permissions plus: delete documents, delete reports, manage users, view audit logs |
|
| `admin` | All editor permissions plus: delete documents, delete reports, manage users, view audit logs |
|
||||||
|
|
||||||
Sessions expire after 24 hours. Session tokens are stored in `httpOnly` cookies.
|
Sessions expire after 24 hours. Session tokens are stored in `httpOnly` cookies.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Home Dashboard — CVE Management
|
### Home — CVE Management
|
||||||
|
|
||||||
The home page is the primary CVE workflow tool.
|
The home page is the primary CVE research and tracking tool.
|
||||||
|
|
||||||
**CVE List**
|
**CVE List**
|
||||||
- Search CVEs by keyword (matches CVE ID, vendor, description)
|
- Search CVEs by keyword (matches CVE ID, vendor, description)
|
||||||
@@ -257,7 +273,7 @@ The home page is the primary CVE workflow tool.
|
|||||||
|
|
||||||
**Archer Ticket Quick Navigation**
|
**Archer Ticket Quick Navigation**
|
||||||
- Archer EXC numbers shown on CVE rows
|
- Archer EXC numbers shown on CVE rows
|
||||||
- Clicking an EXC badge navigates to the Reporting page with that EXC number pre-filtered
|
- Clicking an EXC badge navigates to the Reporting page pre-filtered to findings with that EXC number
|
||||||
|
|
||||||
**Calendar Widget**
|
**Calendar Widget**
|
||||||
- Shows current month with red dot indicators on dates where Ivanti findings are due
|
- Shows current month with red dot indicators on dates where Ivanti findings are due
|
||||||
@@ -271,93 +287,128 @@ The Reporting page is the core operational view for remediation tracking. It int
|
|||||||
|
|
||||||
#### Syncing Data
|
#### Syncing Data
|
||||||
|
|
||||||
Click **Sync** in the top-right of the page to pull the latest findings from Ivanti. The sync:
|
Click **Sync** (top right) to pull the latest findings from Ivanti. The sync:
|
||||||
1. Fetches all open host findings matching your BU filters and severity range (8.5–9.9)
|
1. Fetches all open host findings matching your BU filters and severity range (8.5–9.9 VRR)
|
||||||
2. Fetches the closed finding count separately
|
2. Fetches the closed finding count separately
|
||||||
3. Sweeps all closed findings to capture FP workflow states (including Approved FPs that are now closed)
|
3. Sweeps closed findings to capture FP workflow states (including Approved FPs now closed)
|
||||||
4. Stores everything in the local SQLite cache
|
4. Stores everything in the local SQLite cache
|
||||||
|
|
||||||
Findings are auto-synced on a 24-hour schedule. The last sync timestamp and status are shown at the top of the page.
|
Findings are also auto-synced on a 24-hour schedule. The last sync timestamp is shown at the top of the page.
|
||||||
|
|
||||||
> **Note:** The Reporting page will show "No data — click Sync to load" until the first sync completes. `IVANTI_API_KEY` must be set in `backend/.env`.
|
> `IVANTI_API_KEY` must be set in `backend/.env` for sync to work.
|
||||||
|
|
||||||
#### Metric Charts
|
#### Metric Charts
|
||||||
|
|
||||||
Four donut charts are shown at the top of the page.
|
|
||||||
|
|
||||||
| Chart | What it shows |
|
| Chart | What it shows |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Open vs Closed** | Total open vs closed host findings. Counts come from the Ivanti API directly (not from the local cache) so closed findings are always reflected even though they aren't stored locally. |
|
| **Open vs Closed** | Total open vs closed host findings direct from the Ivanti API |
|
||||||
| **Action Coverage** | Findings broken down by action taken: **FP Request** (has an FP# workflow ticket) · **Archer Exception** (has an EXC- number in notes) · **Pending** (no action yet). Click any segment to filter the table. |
|
| **Action Coverage** | Findings by action taken: FP Request · Archer Exception · Pending. Click a segment to filter the table. |
|
||||||
| **FP Finding Status** | How many *findings* fall into each FP workflow state (Actionable, Requested, Reworked, Approved, Rejected, Expired, Unknown). Includes closed findings — an Approved FP closes the finding and would be invisible otherwise. |
|
| **FP Finding Status** | How many *findings* are in each FP workflow state (Actionable, Requested, Reworked, Approved, Rejected, Expired) |
|
||||||
| **FP Workflow Status** | How many *unique FP# ticket IDs* are in each state. One FP# ticket can cover many findings; this chart counts tickets, not findings. |
|
| **FP Workflow Status** | How many *unique FP# ticket IDs* are in each state — one ticket can cover many findings |
|
||||||
|
|
||||||
#### Findings Table
|
#### Findings Table
|
||||||
|
|
||||||
The table shows all open findings from the cache. Each row represents a single host finding.
|
Each row represents a single Ivanti host finding.
|
||||||
|
|
||||||
**Columns**
|
|
||||||
|
|
||||||
| Column | Description |
|
| Column | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Finding ID | Ivanti finding identifier |
|
| Finding ID | Ivanti finding identifier |
|
||||||
| Severity | Numerical VRR score with group label (CRITICAL / HIGH) |
|
| Severity | Numerical VRR score with group label (CRITICAL / HIGH) |
|
||||||
| Title | Vulnerability title |
|
| Title | Vulnerability title |
|
||||||
| CVEs | Associated CVE IDs — up to 2 shown, remainder as "+N" |
|
| CVEs | Associated CVE IDs — up to 2 shown, remainder as "+N" badge |
|
||||||
| Host | Hostname — inline editable (see Overrides below) |
|
| Host | Hostname — inline editable |
|
||||||
| IP Address | Host IP address |
|
| IP Address | Host IP address |
|
||||||
| DNS | DNS/FQDN — inline editable |
|
| DNS | DNS/FQDN — inline editable |
|
||||||
| Due Date | Remediation due date; red if overdue, amber if within 30 days |
|
| Due Date | Remediation due date; red if overdue, amber if within 30 days |
|
||||||
| SLA | SLA status: OVERDUE / AT_RISK / WITHIN_SLA |
|
| SLA | SLA status: OVERDUE / AT_RISK / WITHIN_SLA |
|
||||||
| BU | Business unit; STEAM rows are highlighted |
|
| BU | Business unit |
|
||||||
| Workflow | FP# ticket ID and state badge — color-coded by state |
|
| Workflow | FP# ticket ID and state badge — colour-coded by urgency |
|
||||||
| Last Found | Last detection date from Ivanti |
|
| Last Found | Last detection date from Ivanti |
|
||||||
| Notes | Free-form notes field — inline editable, persists across syncs |
|
| Notes | Free-form notes — inline editable, persists across syncs |
|
||||||
|
|
||||||
**Column Management**
|
**Inline editing:** Click a Host or DNS cell to override the Ivanti value. An amber dot (●) marks overridden cells; use the revert button (↻) to restore the original. Overrides survive re-syncs.
|
||||||
|
|
||||||
Click the **Columns** button to open the column manager:
|
**Filtering:** Click ⊙ on any column header for multi-select filtering. The `— empty —` option filters to findings with no value in that column. Multiple filters are ANDed. The Action Coverage chart also acts as a filter.
|
||||||
- Toggle column visibility with the eye icon
|
|
||||||
- Drag rows to reorder columns
|
|
||||||
- Column order and visibility persist to `localStorage`
|
|
||||||
|
|
||||||
**Sorting**
|
**Column management:** Toggle visibility and drag to reorder via the **Columns** button. Order and visibility persist to `localStorage`.
|
||||||
|
|
||||||
Click any sortable column header to sort ascending; click again to sort descending.
|
**Export:** Click **Export** to download the current filtered view as CSV or XLSX.
|
||||||
|
|
||||||
**Filtering**
|
---
|
||||||
|
|
||||||
Click the filter icon (⊙) on any filterable column header to open a filter dropdown:
|
### Ivanti Queue
|
||||||
- Search box to narrow options
|
|
||||||
- Multi-select checkboxes — all values are selected by default
|
|
||||||
- **`— empty —`** option at the top: selects findings where the cell has no value (e.g., filter the Workflow column to `— empty —` to see all findings with no FP ticket assigned)
|
|
||||||
- "Select All" and "Clear" bulk buttons
|
|
||||||
- Multiple column filters work as AND (all must match)
|
|
||||||
- Active filter badge and "Clear Filters" button appear when filters are applied
|
|
||||||
|
|
||||||
The **Action Coverage** donut chart also acts as a filter — click a segment to filter the table to that action type.
|
A personal staging list for batch-processing FP, Archer, and CARD workflows without context-switching into Ivanti mid-review.
|
||||||
|
|
||||||
**Inline Editing**
|
**Adding items:** Check the checkbox at the far left of any finding row. A popover appears:
|
||||||
|
- For **FP** and **Archer** items: enter the Vendor / Platform (e.g., "Juniper MX", "Cisco IOS-XE")
|
||||||
|
- For **CARD** items: no vendor entry required — the IP address is captured automatically
|
||||||
|
- Select the workflow type: **FP**, **Archer**, or **CARD**
|
||||||
|
- Click **Add to Queue** — the row checkbox turns solid blue
|
||||||
|
|
||||||
- **Hostname / DNS**: Click a cell to edit. An amber dot (●) indicates the value has been overridden from what Ivanti reported. Use the revert button (↻) to restore the original value. Changes save on blur or Enter; Escape cancels.
|
**Queue panel:** Click the **Queue** button (top right of Reporting page) to open the slide-out panel:
|
||||||
- **Notes**: Click to edit. Saves on blur. Maximum 255 characters. Notes survive cache refreshes.
|
- **CARD** items appear at the top in their own section with the IP address displayed
|
||||||
|
- **FP and Archer** items are grouped alphabetically by vendor below
|
||||||
|
- Badges show workflow type: amber = FP, sky = Archer, green = CARD
|
||||||
|
|
||||||
**Exporting**
|
**Working the queue:**
|
||||||
|
- Check the green checkbox on an item to mark it complete (strikethrough at reduced opacity)
|
||||||
|
- Delete individual items with the trash icon, or select multiple and use **Delete (N)**
|
||||||
|
- **Clear Completed** removes all marked-complete items at once
|
||||||
|
|
||||||
Click the **Export** button to download the current view (filtered, sorted, visible columns only):
|
Queue items are stored in the database, are **personal to your login**, and persist across sessions and page refreshes.
|
||||||
- **CSV** — UTF-8 with BOM for Excel compatibility
|
|
||||||
- **Excel (.xlsx)** — Auto-fitted column widths
|
|
||||||
|
|
||||||
Filename format: `findings-export-YYYY-MM-DD.csv` / `.xlsx`
|
---
|
||||||
|
|
||||||
|
### Compliance — AEO Posture
|
||||||
|
|
||||||
|
The Compliance page tracks NTS-AEO team posture against the AEO compliance framework using weekly xlsx reports exported from the NTS_AEO reporting system.
|
||||||
|
|
||||||
|
#### Upload Workflow
|
||||||
|
|
||||||
|
Editors and admins can upload a new compliance report via the **Upload Report** button:
|
||||||
|
|
||||||
|
1. Drop or browse for the `NTS_AEO_YYYY_MM_DD.xlsx` file
|
||||||
|
2. The report is parsed server-side and a **diff preview** is shown — new violations, resolved items, and recurring items since the last upload
|
||||||
|
3. Click **Confirm Upload** to commit. The upload is recorded and the device table updates immediately.
|
||||||
|
|
||||||
|
The report date is extracted automatically from the filename.
|
||||||
|
|
||||||
|
#### Metric Health Cards
|
||||||
|
|
||||||
|
Each AEO metric (e.g., `2.3.4i`, `5.2.4`) is shown as a health card displaying:
|
||||||
|
- Compliance percentage vs target
|
||||||
|
- Status: Meets/Exceeds Target · Within 15% of Target · Below 15% of Target
|
||||||
|
|
||||||
|
Click a card to filter the device table to only devices failing that metric.
|
||||||
|
|
||||||
|
#### Device Table
|
||||||
|
|
||||||
|
Shows all devices currently failing one or more metrics (Active tab) or previously resolved (Resolved tab). Columns: Hostname, IP Address, Type, Failing Metrics, Times Seen. Click a row to open the detail panel.
|
||||||
|
|
||||||
|
#### Detail Panel
|
||||||
|
|
||||||
|
A slide-out panel for a selected device showing:
|
||||||
|
- **Failing Metrics** — each metric with surfaced extra fields (CVEs, SLA status, due date, OS, EoL, Splunk last seen, MFA software)
|
||||||
|
- For **2.3.x vulnerability metrics**: the `Ivanti_Vulnerability_ID` is displayed with a **View in Reporting →** button that navigates directly to the Reporting page
|
||||||
|
- **Resolved Metrics** — previously failing metrics now back in compliance
|
||||||
|
- **History** — how many times the device has appeared on the report and since when
|
||||||
|
- **Notes** — timestamped notes per metric with a multi-metric selector if multiple metrics are failing
|
||||||
|
|
||||||
|
Notes persist across uploads and are keyed to the device hostname and metric ID.
|
||||||
|
|
||||||
|
#### Teams
|
||||||
|
|
||||||
|
Only **STEAM** and **ACCESS-ENG** teams are tracked. The team selector at the top of the page switches context between them.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Knowledge Base
|
### Knowledge Base
|
||||||
|
|
||||||
A document library for internal reference material such as policies, runbooks, and vendor advisories.
|
A document library for internal reference material — policies, runbooks, vendor advisories, and process guides.
|
||||||
|
|
||||||
- Upload documents with a title, optional description, and category
|
- Upload documents with a title, optional description, and category
|
||||||
- View documents inline in the browser (PDFs render in an iframe; Markdown files are rendered as HTML)
|
- View documents inline in the browser (PDFs render in an iframe; Markdown files render as HTML)
|
||||||
- Download any document
|
- Download any document
|
||||||
- Filter and browse by category
|
- Filter and browse by category
|
||||||
- Editors and admins can upload and delete; all authenticated users can view
|
- Editors and admins can upload and delete; all authenticated users can view
|
||||||
@@ -366,6 +417,12 @@ Allowed file types: PDF, Markdown, TXT, Office documents (DOC, DOCX, XLS, XLSX,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Exports
|
||||||
|
|
||||||
|
Bulk export tools for reports and data extracts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Archer Risk Acceptance Tickets
|
### Archer Risk Acceptance Tickets
|
||||||
|
|
||||||
Track Archer exception tickets (EXC numbers) linked to specific CVE/vendor pairs.
|
Track Archer exception tickets (EXC numbers) linked to specific CVE/vendor pairs.
|
||||||
@@ -374,27 +431,20 @@ Track Archer exception tickets (EXC numbers) linked to specific CVE/vendor pairs
|
|||||||
- Statuses: `Draft`, `Open`, `Under Review`, `Accepted`
|
- Statuses: `Draft`, `Open`, `Under Review`, `Accepted`
|
||||||
- Optional Archer URL field for deep-linking to the Archer record
|
- Optional Archer URL field for deep-linking to the Archer record
|
||||||
- Filter tickets by CVE ID, vendor, or status
|
- Filter tickets by CVE ID, vendor, or status
|
||||||
- EXC numbers are unique across the system
|
- Clicking an EXC badge on the Home page navigates to the Reporting page pre-filtered to findings with that EXC number in their notes
|
||||||
- Clicking an EXC number on the home page navigates directly to the Reporting page with that EXC pre-filtered
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Weekly Reports
|
### Weekly Reports
|
||||||
|
|
||||||
Editors and admins can upload weekly vulnerability reports as `.xlsx` files. The report is processed by a Python script (`backend/scripts/split_cve_report.py`) that:
|
Editors and admins can upload weekly vulnerability reports as `.xlsx` files. The report is processed by `backend/scripts/split_cve_report.py` which splits rows where multiple CVE IDs are comma-separated in the `CVE ID` column into individual rows.
|
||||||
|
|
||||||
1. Reads the `Vulnerabilities` sheet
|
Both the original and processed files can be downloaded from the weekly reports list. Admins can delete old report records and associated files.
|
||||||
2. Splits rows where multiple CVE IDs are comma-separated in the `CVE ID` column into individual rows
|
|
||||||
3. Saves the processed file alongside the original
|
|
||||||
|
|
||||||
Both the original and processed files can be downloaded from the weekly reports list. Only the most recently uploaded report is marked as current. Admins can delete old report records and their associated files.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### User Management (Admin)
|
### User Management (Admin)
|
||||||
|
|
||||||
Admins can manage user accounts from the UI:
|
|
||||||
|
|
||||||
- Create users with a role assignment
|
- Create users with a role assignment
|
||||||
- Change username, email, password, role, or active status
|
- Change username, email, password, role, or active status
|
||||||
- Deactivating a user immediately invalidates all their active sessions
|
- Deactivating a user immediately invalidates all their active sessions
|
||||||
@@ -404,12 +454,35 @@ Admins can manage user accounts from the UI:
|
|||||||
|
|
||||||
### Audit Log (Admin)
|
### Audit Log (Admin)
|
||||||
|
|
||||||
Every state-changing action is recorded with the user identity, IP address, action type, target entity, and a before/after details payload. Admins can view the log with filtering by user, action type, entity type, and date range. Results are paginated (25 per page).
|
Every state-changing action is recorded with the user identity, IP address, action type, target entity, and a before/after payload. Admins can view the log filtered by user, action type, entity type, and date range. Results are paginated (25 per page).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
|
### `backend/scripts/parse_compliance_xlsx.py`
|
||||||
|
|
||||||
|
Called automatically by the compliance upload flow. Parses the NTS_AEO xlsx report and outputs structured JSON to stdout for consumption by the Node compliance route.
|
||||||
|
|
||||||
|
- Reads all detail sheets; skips `Summary` and `CMDB_9box`
|
||||||
|
- Filters to rows where `Compliant == False`
|
||||||
|
- Extracts hostname, IP, device type, team, and metric ID per row
|
||||||
|
- Captures all non-core columns in `extra_json` (CVEs, SLA status, OS, EoL, Splunk, MFA, Ivanti_Vulnerability_ID, etc.)
|
||||||
|
- Parses `Summary` sheet for per-team metric health (compliance_pct, target, status)
|
||||||
|
- Extracts report date from the filename (`NTS_AEO_YYYY_MM_DD.xlsx`)
|
||||||
|
|
||||||
|
**Dependencies:** `pandas>=2.0.0`, `openpyxl>=3.0.0`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `backend/scripts/split_cve_report.py`
|
||||||
|
|
||||||
|
Called automatically by the weekly report upload flow. Splits multi-CVE rows in the uploaded Excel report into one row per CVE ID. Not intended to be run manually.
|
||||||
|
|
||||||
|
**Dependencies:** `pandas>=2.0.0`, `openpyxl>=3.0.0`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `backend/scripts/import_notes_from_csv.py`
|
### `backend/scripts/import_notes_from_csv.py`
|
||||||
|
|
||||||
Bulk-import notes into the findings cache from a CSV file. Useful for onboarding existing notes or migrating from a spreadsheet.
|
Bulk-import notes into the findings cache from a CSV file. Useful for onboarding existing notes or migrating from a spreadsheet.
|
||||||
@@ -449,14 +522,6 @@ python3 import_notes_from_csv.py input.csv --db /path/to/cve_database.db
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `backend/scripts/split_cve_report.py`
|
|
||||||
|
|
||||||
Called automatically by the weekly report upload flow. Not intended to be run manually. Splits multi-CVE rows in the uploaded Excel report into one row per CVE ID.
|
|
||||||
|
|
||||||
**Dependencies:** `pandas>=2.0.0`, `openpyxl>=3.0.0`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
All endpoints are prefixed with `/api`. All endpoints except `/api/auth/login` and `/api/auth/logout` require a valid session cookie.
|
All endpoints are prefixed with `/api`. All endpoints except `/api/auth/login` and `/api/auth/logout` require a valid session cookie.
|
||||||
@@ -499,24 +564,47 @@ All endpoints are prefixed with `/api`. All endpoints except `/api/auth/login` a
|
|||||||
| GET | `/api/nvd/lookup/:cveId` | viewer+ | Look up a single CVE in the NVD 2.0 API |
|
| GET | `/api/nvd/lookup/:cveId` | viewer+ | Look up a single CVE in the NVD 2.0 API |
|
||||||
| POST | `/api/cves/nvd-sync` | editor+ | Bulk update CVE metadata from NVD |
|
| POST | `/api/cves/nvd-sync` | editor+ | Bulk update CVE metadata from NVD |
|
||||||
|
|
||||||
### Ivanti / RiskSense — Workflows
|
### Ivanti — Host Findings
|
||||||
|
|
||||||
| Method | Path | Role | Description |
|
|
||||||
|---|---|---|---|
|
|
||||||
| GET | `/api/ivanti/workflows` | viewer+ | Get cached workflow data (total, list, sync status) |
|
|
||||||
| POST | `/api/ivanti/workflows/sync` | viewer+ | Trigger an immediate workflow sync from Ivanti |
|
|
||||||
|
|
||||||
### Ivanti / RiskSense — Host Findings
|
|
||||||
|
|
||||||
| Method | Path | Role | Description |
|
| Method | Path | Role | Description |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| GET | `/api/ivanti/findings` | viewer+ | Get cached findings with notes and overrides merged in |
|
| GET | `/api/ivanti/findings` | viewer+ | Get cached findings with notes and overrides merged in |
|
||||||
| POST | `/api/ivanti/findings/sync` | viewer+ | Trigger an immediate findings sync from Ivanti |
|
| POST | `/api/ivanti/findings/sync` | viewer+ | Trigger an immediate findings sync from Ivanti |
|
||||||
| GET | `/api/ivanti/findings/counts` | viewer+ | Open vs closed finding totals |
|
| GET | `/api/ivanti/findings/counts` | viewer+ | Open vs closed finding totals |
|
||||||
| GET | `/api/ivanti/findings/fp-workflow-counts` | viewer+ | FP workflow state breakdown — returns `findingCounts`, `findingTotal`, `idCounts`, `idTotal` |
|
| GET | `/api/ivanti/findings/fp-workflow-counts` | viewer+ | FP workflow state breakdown |
|
||||||
| PUT | `/api/ivanti/findings/:findingId/override` | editor+ | Override `hostName` or `dns` for a finding; empty value clears the override |
|
| PUT | `/api/ivanti/findings/:findingId/override` | editor+ | Override `hostName` or `dns`; empty value clears the override |
|
||||||
| PUT | `/api/ivanti/findings/:findingId/note` | viewer+ | Save or update a finding note (max 255 chars) |
|
| PUT | `/api/ivanti/findings/:findingId/note` | viewer+ | Save or update a finding note (max 255 chars) |
|
||||||
|
|
||||||
|
### Ivanti — Workflows
|
||||||
|
|
||||||
|
| Method | Path | Role | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/ivanti/workflows` | viewer+ | Get cached workflow data |
|
||||||
|
| POST | `/api/ivanti/workflows/sync` | viewer+ | Trigger an immediate workflow sync |
|
||||||
|
|
||||||
|
### Ivanti Queue
|
||||||
|
|
||||||
|
| Method | Path | Role | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/ivanti/queue` | viewer+ | Get all queue items for the current user |
|
||||||
|
| POST | `/api/ivanti/queue` | editor+ | Add a finding to the queue |
|
||||||
|
| PATCH | `/api/ivanti/queue/:id` | editor+ | Update a queue item (mark complete, edit vendor/type) |
|
||||||
|
| DELETE | `/api/ivanti/queue/:id` | editor+ | Delete a single queue item |
|
||||||
|
| DELETE | `/api/ivanti/queue` | editor+ | Delete multiple queue items (body: `{ ids: [...] }`) |
|
||||||
|
|
||||||
|
### Compliance
|
||||||
|
|
||||||
|
| Method | Path | Role | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| POST | `/api/compliance/preview` | editor+ | Parse an xlsx upload and return diff + temp file path |
|
||||||
|
| POST | `/api/compliance/commit` | editor+ | Commit a previewed upload to the database |
|
||||||
|
| GET | `/api/compliance/uploads` | viewer+ | List all compliance upload records |
|
||||||
|
| GET | `/api/compliance/summary` | viewer+ | Metric health summary; `?team=STEAM` |
|
||||||
|
| GET | `/api/compliance/items` | viewer+ | Device list; `?team=STEAM&status=active` |
|
||||||
|
| GET | `/api/compliance/items/:hostname` | viewer+ | Full detail for a device (metrics + notes) |
|
||||||
|
| GET | `/api/compliance/notes/:hostname/:metricId` | viewer+ | Notes for a specific hostname/metric |
|
||||||
|
| POST | `/api/compliance/notes` | editor+ | Add a note for a hostname/metric |
|
||||||
|
|
||||||
### Weekly Reports
|
### Weekly Reports
|
||||||
|
|
||||||
| Method | Path | Role | Description |
|
| Method | Path | Role | Description |
|
||||||
@@ -568,7 +656,7 @@ All endpoints are prefixed with `/api`. All endpoints except `/api/auth/login` a
|
|||||||
| Method | Path | Role | Description |
|
| Method | Path | Role | Description |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| GET | `/api/vendors` | viewer+ | List all distinct vendor names |
|
| GET | `/api/vendors` | viewer+ | List all distinct vendor names |
|
||||||
| GET | `/api/stats` | viewer+ | Dashboard statistics (total, critical count, addressed count, document count) |
|
| GET | `/api/stats` | viewer+ | Dashboard statistics |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -580,15 +668,14 @@ cve-dashboard/
|
|||||||
├── stop-servers.sh # Stop all servers
|
├── stop-servers.sh # Stop all servers
|
||||||
│
|
│
|
||||||
├── backend/
|
├── backend/
|
||||||
│ ├── server.js # Express app — routes, middleware, file upload, security headers
|
│ ├── server.js # Express app — routes, middleware, security headers
|
||||||
│ ├── setup.js # One-time DB initialization and default admin creation
|
│ ├── setup.js # One-time DB initialization and default admin creation
|
||||||
│ ├── cve_database.db # SQLite database (gitignored)
|
│ ├── cve_database.db # SQLite database (gitignored)
|
||||||
│ ├── uploads/ # File storage root (gitignored)
|
│ ├── uploads/ # File storage root (gitignored)
|
||||||
│ │ ├── <CVE-ID>/
|
│ │ ├── <CVE-ID>/<vendor>/ # CVE documents
|
||||||
│ │ │ └── <vendor>/ # CVE documents stored here
|
│ │ ├── weekly_reports/ # Uploaded vulnerability reports
|
||||||
│ │ ├── weekly_reports/ # Uploaded vulnerability reports
|
│ │ ├── knowledge_base/ # Knowledge base documents
|
||||||
│ │ ├── knowledge_base/ # Knowledge base documents
|
│ │ └── temp/ # Temporary upload staging
|
||||||
│ │ └── temp/ # Temporary upload staging directory
|
|
||||||
│ ├── routes/
|
│ ├── routes/
|
||||||
│ │ ├── auth.js # Login, logout, session check
|
│ │ ├── auth.js # Login, logout, session check
|
||||||
│ │ ├── users.js # User CRUD (admin)
|
│ │ ├── users.js # User CRUD (admin)
|
||||||
@@ -598,7 +685,9 @@ cve-dashboard/
|
|||||||
│ │ ├── knowledgeBase.js # Knowledge base document management
|
│ │ ├── knowledgeBase.js # Knowledge base document management
|
||||||
│ │ ├── archerTickets.js # Archer EXC ticket CRUD
|
│ │ ├── archerTickets.js # Archer EXC ticket CRUD
|
||||||
│ │ ├── ivantiWorkflows.js # Ivanti workflow batch sync and cache
|
│ │ ├── ivantiWorkflows.js # Ivanti workflow batch sync and cache
|
||||||
│ │ └── ivantiFindings.js # Ivanti host findings sync, notes, overrides, FP counts
|
│ │ ├── ivantiFindings.js # Ivanti host findings sync, notes, overrides, FP counts
|
||||||
|
│ │ ├── ivantiTodoQueue.js # Ivanti Queue — personal FP/Archer/CARD staging list
|
||||||
|
│ │ └── compliance.js # AEO compliance upload, diff, device tracking, notes
|
||||||
│ ├── middleware/
|
│ ├── middleware/
|
||||||
│ │ └── auth.js # requireAuth and requireRole middleware
|
│ │ └── auth.js # requireAuth and requireRole middleware
|
||||||
│ ├── helpers/
|
│ ├── helpers/
|
||||||
@@ -608,12 +697,17 @@ cve-dashboard/
|
|||||||
│ │ ├── add_weekly_reports_table.js
|
│ │ ├── add_weekly_reports_table.js
|
||||||
│ │ ├── add_knowledge_base_table.js
|
│ │ ├── add_knowledge_base_table.js
|
||||||
│ │ ├── add_archer_tickets_table.js
|
│ │ ├── add_archer_tickets_table.js
|
||||||
│ │ ├── add_ivanti_sync_table.js # Ivanti workflow cache table
|
│ │ ├── add_ivanti_sync_table.js
|
||||||
│ │ └── add_ivanti_findings_tables.js # Findings cache, notes, counts, overrides tables
|
│ │ ├── add_ivanti_findings_tables.js
|
||||||
|
│ │ ├── add_ivanti_todo_queue_table.js # Ivanti Queue table
|
||||||
|
│ │ ├── add_card_workflow_type.js # CARD workflow type support
|
||||||
|
│ │ ├── add_todo_queue_ip_address.js # IP address column on queue items
|
||||||
|
│ │ └── add_compliance_tables.js # AEO compliance tables
|
||||||
│ └── scripts/
|
│ └── scripts/
|
||||||
│ ├── split_cve_report.py # Splits multi-CVE rows in Excel reports
|
│ ├── parse_compliance_xlsx.py # Parses NTS_AEO xlsx compliance reports
|
||||||
│ ├── import_notes_from_csv.py # Bulk-import finding notes from CSV
|
│ ├── split_cve_report.py # Splits multi-CVE rows in weekly reports
|
||||||
│ └── requirements.txt # pandas, openpyxl (weekly report processing only)
|
│ ├── import_notes_from_csv.py # Bulk-import finding notes from CSV
|
||||||
|
│ └── requirements.txt # pandas, openpyxl
|
||||||
│
|
│
|
||||||
└── frontend/
|
└── frontend/
|
||||||
└── src/
|
└── src/
|
||||||
@@ -628,13 +722,16 @@ cve-dashboard/
|
|||||||
├── CalendarWidget.js # Due-date calendar with Ivanti finding indicators
|
├── CalendarWidget.js # Due-date calendar with Ivanti finding indicators
|
||||||
├── UserManagement.js # Admin user management panel
|
├── UserManagement.js # Admin user management panel
|
||||||
├── AuditLog.js # Admin audit log viewer
|
├── AuditLog.js # Admin audit log viewer
|
||||||
├── NvdSyncModal.js # Bulk NVD sync dialog with review/apply flow
|
├── NvdSyncModal.js # Bulk NVD sync dialog
|
||||||
├── KnowledgeBaseModal.js # Knowledge base upload/list modal
|
├── KnowledgeBaseModal.js # Knowledge base upload/list modal
|
||||||
├── KnowledgeBaseViewer.js # Inline document viewer
|
├── KnowledgeBaseViewer.js # Inline document viewer
|
||||||
└── pages/
|
└── pages/
|
||||||
├── ReportingPage.js # Host findings: charts, table, filters, export
|
├── ReportingPage.js # Host findings: charts, table, queue, export
|
||||||
├── KnowledgeBasePage.js # Knowledge base page (placeholder)
|
├── CompliancePage.js # AEO compliance: metric cards, device table
|
||||||
└── ExportsPage.js # Exports page (placeholder)
|
├── ComplianceUploadModal.js # xlsx upload with diff preview
|
||||||
|
├── ComplianceDetailPanel.js # Per-device metrics, history, notes
|
||||||
|
├── KnowledgeBasePage.js # Knowledge base page
|
||||||
|
└── ExportsPage.js # Exports page
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -657,25 +754,30 @@ cve-dashboard/
|
|||||||
|
|
||||||
### Feature tables (added by migrations)
|
### Feature tables (added by migrations)
|
||||||
|
|
||||||
**`weekly_reports`** — Metadata for uploaded vulnerability reports. Tracks original and processed file paths, row counts, uploader, and a `is_current` flag.
|
**`weekly_reports`** — Metadata for uploaded vulnerability reports. Tracks original and processed file paths, row counts, uploader, and an `is_current` flag.
|
||||||
|
|
||||||
**`knowledge_base`** — Document library entries with title, slug, category, description, and file metadata.
|
**`knowledge_base`** — Document library entries with title, slug, category, description, and file metadata.
|
||||||
|
|
||||||
**`archer_tickets`** — Archer EXC exception tickets linked to CVE/vendor pairs. `UNIQUE(exc_number)`. Foreign key `(cve_id, vendor)` with CASCADE delete.
|
**`archer_tickets`** — Archer EXC exception tickets linked to CVE/vendor pairs. `UNIQUE(exc_number)`.
|
||||||
|
|
||||||
**`ivanti_sync_state`** — Single-row cache (id=1) for Ivanti workflow batch data: total count, JSON array of workflows, sync timestamp, sync status.
|
**`ivanti_sync_state`** — Single-row cache for Ivanti workflow batch data.
|
||||||
|
|
||||||
**`ivanti_findings_cache`** — Single-row cache (id=1) for Ivanti host findings: total count, JSON array of slimmed finding objects, sync timestamp, sync status.
|
**`ivanti_findings_cache`** — Single-row cache for Ivanti host findings.
|
||||||
|
|
||||||
**`ivanti_finding_notes`** — Persistent per-finding notes keyed by finding ID. Survives findings cache refreshes. `UNIQUE(finding_id)`.
|
**`ivanti_finding_notes`** — Persistent per-finding notes keyed by finding ID. Survives cache refreshes. `UNIQUE(finding_id)`.
|
||||||
|
|
||||||
**`ivanti_counts_cache`** — Single-row cache (id=1) for finding metrics:
|
**`ivanti_counts_cache`** — Single-row cache for finding metrics: open/closed counts, FP workflow state breakdowns by finding and by unique ticket ID.
|
||||||
- `open_count` / `closed_count` — total open and closed findings
|
|
||||||
- `fp_workflow_counts_json` — JSON object mapping FP workflow state → number of findings
|
|
||||||
- `fp_id_counts_json` — JSON object mapping FP workflow state → number of unique FP# ticket IDs
|
|
||||||
|
|
||||||
**`ivanti_finding_overrides`** — Editor-applied overrides for `hostName` and `dns` fields. `UNIQUE(finding_id, field)`.
|
**`ivanti_finding_overrides`** — Editor-applied overrides for `hostName` and `dns` fields. `UNIQUE(finding_id, field)`.
|
||||||
|
|
||||||
|
**`ivanti_todo_queue`** — Personal per-user queue of findings staged for FP, Archer, or CARD processing. Keyed by `(user_id, finding_id)`.
|
||||||
|
|
||||||
|
**`compliance_uploads`** — Record of each compliance xlsx upload: filename, report date, uploader, timestamp, and new/resolved/recurring counts.
|
||||||
|
|
||||||
|
**`compliance_items`** — One row per device/metric violation. Tracks hostname, IP, device type, team, metric ID, category, `extra_json` (all non-core xlsx columns), status (active/resolved), first seen upload, and times seen. Identity key: `(hostname, metric_id)`.
|
||||||
|
|
||||||
|
**`compliance_notes`** — Timestamped notes per hostname/metric. Multiple notes per combination are supported. Foreign-key linked to compliance items.
|
||||||
|
|
||||||
### View
|
### View
|
||||||
|
|
||||||
**`cve_document_status`** — Aggregates document counts per CVE/vendor and derives a `compliance_status` (`Complete` when an advisory is present, otherwise `Missing Required Docs`).
|
**`cve_document_status`** — Aggregates document counts per CVE/vendor and derives a `compliance_status` (`Complete` when an advisory is present, otherwise `Missing Required Docs`).
|
||||||
@@ -703,13 +805,13 @@ cve-dashboard/
|
|||||||
- Status must be one of: `Open`, `Addressed`, `In Progress`, `Resolved`
|
- Status must be one of: `Open`, `Addressed`, `In Progress`, `Resolved`
|
||||||
- Archer EXC numbers must match `/^EXC-\d+$/`
|
- Archer EXC numbers must match `/^EXC-\d+$/`
|
||||||
- Finding override field must be one of: `hostName`, `dns`
|
- Finding override field must be one of: `hostName`, `dns`
|
||||||
- All database operations use prepared statements (no string interpolation in SQL)
|
- All database operations use prepared statements — no string interpolation in SQL
|
||||||
|
|
||||||
### Error handling
|
### Error handling
|
||||||
|
|
||||||
- 500 responses never expose internal error messages to the client
|
- 500 responses never expose internal error messages to the client
|
||||||
- Full errors are logged server-side only
|
- Full errors are logged server-side only
|
||||||
- Descriptive 400/409 responses are safe as they contain only application-authored validation messages
|
- Descriptive 400/409 responses contain only application-authored validation messages
|
||||||
|
|
||||||
### Security headers
|
### Security headers
|
||||||
|
|
||||||
@@ -729,7 +831,7 @@ Applied to all responses:
|
|||||||
|
|
||||||
## Migrations
|
## Migrations
|
||||||
|
|
||||||
Migrations are standalone Node.js scripts that modify the database directly. Run them in the listed order on a fresh install. They use `CREATE TABLE IF NOT EXISTS` so they are safe to re-run if needed.
|
Migrations are standalone Node.js scripts. Run them in the listed order on a fresh install. All use `CREATE TABLE IF NOT EXISTS` or `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` and are safe to re-run.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
@@ -738,12 +840,16 @@ node migrations/add_knowledge_base_table.js
|
|||||||
node migrations/add_archer_tickets_table.js
|
node migrations/add_archer_tickets_table.js
|
||||||
node migrations/add_ivanti_sync_table.js
|
node migrations/add_ivanti_sync_table.js
|
||||||
node migrations/add_ivanti_findings_tables.js
|
node migrations/add_ivanti_findings_tables.js
|
||||||
|
node migrations/add_ivanti_todo_queue_table.js
|
||||||
|
node migrations/add_card_workflow_type.js
|
||||||
|
node migrations/add_todo_queue_ip_address.js
|
||||||
|
node migrations/add_compliance_tables.js
|
||||||
```
|
```
|
||||||
|
|
||||||
For an existing deployment upgrading from an earlier schema, check the legacy migration scripts in `backend/`:
|
For deployments upgrading from an older schema, the following legacy migration scripts are also available in `backend/`:
|
||||||
|
|
||||||
- `migrate_multivendor.js` — Adds multi-vendor support to an older single-vendor schema
|
- `migrate_multivendor.js` — Adds multi-vendor support to an older single-vendor schema
|
||||||
- `migrate-audit-log.js` — Adds the `audit_logs` table to pre-auth deployments
|
- `migrate-audit-log.js` — Adds the `audit_logs` table to pre-auth deployments
|
||||||
- `migrate-to-1.1.js` — General 1.0 → 1.1 schema update
|
- `migrate-to-1.1.js` — General 1.0 → 1.1 schema update
|
||||||
|
|
||||||
> The Ivanti FP workflow count columns (`fp_workflow_counts_json`, `fp_id_counts_json`) are added automatically via `ALTER TABLE ... ADD COLUMN` each time the server starts. These statements are idempotent — the error for a duplicate column is silently ignored.
|
> Several columns (`fp_workflow_counts_json`, `fp_id_counts_json`, `seen_count`, `summary_json`) are added automatically via idempotent `ALTER TABLE` statements each time the server starts. No manual re-run is needed.
|
||||||
|
|||||||
183
docs/security-posture-workflow-diagrams.md
Normal file
183
docs/security-posture-workflow-diagrams.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Security Posture Workflow — Diagrams
|
||||||
|
|
||||||
|
Mermaid diagrams for the Host Finding Review & Remediation process.
|
||||||
|
Renders natively in GitHub, GitLab, and most modern documentation tools.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Diagram 1 — Host Finding Review Workflow (Steps 1–5)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
START([Open Reporting Page]) --> SYNC
|
||||||
|
|
||||||
|
SYNC["① Sync & Sort<br/>Click Sync · Sort Due Date ascending"]
|
||||||
|
SYNC --> DUE{Overdue<br/>findings?}
|
||||||
|
DUE -->|Yes — start here| HOST
|
||||||
|
DUE -->|No — start with amber| HOST
|
||||||
|
|
||||||
|
HOST["② Identify the Host<br/>Verify IP in IPControl / Infoblox"]
|
||||||
|
HOST --> CORRECT{Hostname<br/>correct?}
|
||||||
|
CORRECT -->|No| EDIT["Inline-edit Host / DNS cell<br/>Amber dot marks the override"]
|
||||||
|
EDIT --> OWN
|
||||||
|
CORRECT -->|Yes| OWN
|
||||||
|
|
||||||
|
OWN["③ Identify Asset Ownership<br/>Check BU column"]
|
||||||
|
OWN --> BU{Our BU?}
|
||||||
|
BU -->|"NTS-AEO-STEAM<br/>or ACCESS-ENG"| CVE
|
||||||
|
BU -->|"Other BU<br/>or blank"| CARD["Add to CARD Queue<br/>☑ checkbox → CARD → Add to Queue"]
|
||||||
|
CARD --> CARD2([Process in dedicated CARD session])
|
||||||
|
|
||||||
|
CVE["④ Review CVEs in the Finding<br/>Up to 2 shown · hover +N badge for more"]
|
||||||
|
CVE --> DBCHECK{CVE in<br/>database?}
|
||||||
|
DBCHECK -->|No| ADDCVE["Create CVE entry on Home page<br/>NVD auto-fill populates details"]
|
||||||
|
ADDCVE --> RESEARCH
|
||||||
|
DBCHECK -->|Yes — review existing notes/docs| RESEARCH
|
||||||
|
|
||||||
|
RESEARCH["Research CVE<br/>Vendor advisory · Cisco Bug Search<br/>Juniper PSN · Support ticket"]
|
||||||
|
RESEARCH --> ACTION
|
||||||
|
|
||||||
|
ACTION["⑤ Determine Required Action"]
|
||||||
|
ACTION --> PATH{What does<br/>research show?}
|
||||||
|
|
||||||
|
PATH -->|"Patch available<br/>FW / SW update"| PA
|
||||||
|
PATH -->|"Fix is config<br/>change only"| PB
|
||||||
|
PATH -->|"Not applicable<br/>to platform / version"| PC
|
||||||
|
PATH -->|"Cannot patch<br/>vendor / EOL / business"| PD
|
||||||
|
|
||||||
|
PA["PATH A — Remediation<br/>Firmware or Software Upgrade"]
|
||||||
|
PA --> PA1["Plan & schedule upgrade<br/>Add note to finding row"]
|
||||||
|
PA1 --> PA2(["Finding drops off after<br/>next Ivanti scan ✓"])
|
||||||
|
|
||||||
|
PB["PATH B — Remediation<br/>Configuration Change"]
|
||||||
|
PB --> PB1["☑ checkbox → Vendor → Archer<br/>Add to Queue"]
|
||||||
|
PB1 --> PB2["Open Archer EXC ticket<br/>in dedicated session"]
|
||||||
|
PB2 --> PB3(["Enter EXC-XXXXX<br/>in finding Notes cell ✓"])
|
||||||
|
|
||||||
|
PC["PATH C — False Positive"]
|
||||||
|
PC --> PC1["Take device screenshot<br/>Hostname · IP · SW version"]
|
||||||
|
PC1 --> PC2["Obtain vendor documentation<br/>advisory / email / support ticket"]
|
||||||
|
PC2 --> PC3["Upload evidence to CVE database<br/>Home page → CVE row → Upload"]
|
||||||
|
PC3 --> PC4["☑ checkbox → Vendor → FP<br/>Add to Queue"]
|
||||||
|
PC4 --> PC5(["Submit FP workflow in Ivanti<br/>in dedicated session ✓"])
|
||||||
|
|
||||||
|
PD["PATH D — Risk Acceptance"]
|
||||||
|
PD --> PD1["Take device screenshot<br/>Collect version info"]
|
||||||
|
PD1 --> PD2{Vendor comms<br/>needed?}
|
||||||
|
PD2 -->|Yes| PD3["Open vendor support ticket<br/>Request patch timeline / mitigations"]
|
||||||
|
PD3 --> PD4
|
||||||
|
PD2 -->|No| PD4["☑ checkbox → Vendor → Archer<br/>Add to Queue"]
|
||||||
|
PD4 --> PD5["Open Archer EXC ticket<br/>in dedicated session"]
|
||||||
|
PD5 --> PD6(["Enter EXC-XXXXX<br/>in finding Notes cell ✓"])
|
||||||
|
|
||||||
|
%% Styling
|
||||||
|
classDef step fill:#1e3a5f,stroke:#0ea5e9,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef decision fill:#1a2e1a,stroke:#10b981,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef pathA fill:#14391f,stroke:#10b981,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef pathB fill:#2d1f14,stroke:#f59e0b,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef pathC fill:#2d1414,stroke:#ef4444,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef pathD fill:#1a1430,stroke:#8b5cf6,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef card fill:#1a2e1a,stroke:#10b981,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef done fill:#0f172a,stroke:#475569,stroke-width:1.5px,color:#64748b
|
||||||
|
|
||||||
|
class SYNC,HOST,OWN,CVE,RESEARCH,ACTION step
|
||||||
|
class DUE,CORRECT,BU,DBCHECK,PATH decision
|
||||||
|
class PA,PA1,PA2 pathA
|
||||||
|
class PB,PB1,PB2,PB3 pathB
|
||||||
|
class PC,PC1,PC2,PC3,PC4,PC5 pathC
|
||||||
|
class PD,PD1,PD2,PD3,PD4,PD5,PD6 pathD
|
||||||
|
class CARD,CARD2 card
|
||||||
|
class EDIT done
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Diagram 2 — FP Workflow Badge Status Decision Tree
|
||||||
|
|
||||||
|
What to do when a finding already has a workflow badge in the Reporting page.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A([Finding in<br/>Reporting Page]) --> B{"Check<br/>Workflow column"}
|
||||||
|
|
||||||
|
B -->|No badge| C["UNTRIAGED<br/>No action on record"]
|
||||||
|
C --> C1(["Follow the<br/>Step 1–5 triage workflow ↑"])
|
||||||
|
|
||||||
|
B -->|"🔵 Blue<br/>Requested"| D["IN FLIGHT<br/>FP submitted · awaiting approval"]
|
||||||
|
D --> D1{"SLA window<br/>approaching?"}
|
||||||
|
D1 -->|No| D2(["Monitor — no action yet ✓"])
|
||||||
|
D1 -->|Yes| D3(["Follow up with<br/>the approver"])
|
||||||
|
|
||||||
|
B -->|"🟡 Amber<br/>Reworked"| E["NEEDS REVISION<br/>Reviewer returned the ticket"]
|
||||||
|
E --> E1["Open ticket in Ivanti<br/>Review feedback"]
|
||||||
|
E1 --> E2(["Update justification<br/>and resubmit"])
|
||||||
|
|
||||||
|
B -->|"🟡 Amber<br/>Actionable"| F["NEEDS RESPONSE<br/>Ticket flagged for team action"]
|
||||||
|
F --> F1(["Open ticket in Ivanti<br/>Respond to the request"])
|
||||||
|
|
||||||
|
B -->|"🔴 Red<br/>Expired"| G["EXCEPTION LAPSED<br/>Finding has re-opened"]
|
||||||
|
G --> G1(["Submit a new FP request<br/>in Ivanti<br/>Reference previous ticket"])
|
||||||
|
|
||||||
|
B -->|"🔴 Red<br/>Rejected"| H["CONFIRMED VULNERABILITY<br/>Security team denied the FP"]
|
||||||
|
H --> H1(["Remediate the vulnerability<br/>Do not resubmit FP<br/>without new evidence"])
|
||||||
|
|
||||||
|
%% Styling
|
||||||
|
classDef trigger fill:#0f172a,stroke:#0ea5e9,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef blue fill:#1e3a5f,stroke:#0ea5e9,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef amber fill:#2d2014,stroke:#f59e0b,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef red fill:#2d1414,stroke:#ef4444,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef none fill:#1a1a2e,stroke:#475569,stroke-width:1.5px,color:#94a3b8
|
||||||
|
classDef done fill:#0f172a,stroke:#334155,stroke-width:1px,color:#64748b
|
||||||
|
|
||||||
|
class A,B trigger
|
||||||
|
class D,D1,D2,D3 blue
|
||||||
|
class E,E1,E2,F,F1 amber
|
||||||
|
class G,G1,H,H1 red
|
||||||
|
class C,C1 none
|
||||||
|
class D2,D3,E2,F1,G1,H1 done
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Diagram 3 — Action Decision Matrix (Quick Reference)
|
||||||
|
|
||||||
|
Condensed view of the five research outcomes and their required actions.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
START(["Research complete<br/>Step 4 done"]) --> Q{"What is the<br/>remediation path?"}
|
||||||
|
|
||||||
|
Q --> R1["Firmware or<br/>Software update available"]
|
||||||
|
R1 --> A1(["No ticket needed<br/>Schedule upgrade<br/>Add note to finding"])
|
||||||
|
|
||||||
|
Q --> R2["Fix is a<br/>configuration change"]
|
||||||
|
R2 --> A2(["Archer EXC ticket required<br/>Stage as Archer in Queue"])
|
||||||
|
|
||||||
|
Q --> R3["Not applicable<br/>to this platform / version"]
|
||||||
|
R3 --> A3(["FP workflow in Ivanti<br/>Evidence in CVE database"])
|
||||||
|
|
||||||
|
Q --> R4["Patch not yet<br/>available from vendor"]
|
||||||
|
R4 --> A4(["Archer EXC ticket<br/>Renew when patch ships"])
|
||||||
|
|
||||||
|
Q --> R5["Device is EOL / EOS<br/>or business constraint"]
|
||||||
|
R5 --> A5(["Archer ticket with<br/>mitigation steps +<br/>remediation plan"])
|
||||||
|
|
||||||
|
Q --> R6["Asset not owned<br/>by our BU"]
|
||||||
|
R6 --> A6(["CARD queue<br/>CARD disposition process"])
|
||||||
|
|
||||||
|
classDef q fill:#1e3a5f,stroke:#0ea5e9,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef green fill:#14391f,stroke:#10b981,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef amber fill:#2d2014,stroke:#f59e0b,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef red fill:#2d1414,stroke:#ef4444,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef teal fill:#0f2d2d,stroke:#14b8a6,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
|
||||||
|
class START,Q q
|
||||||
|
class R1,A1 green
|
||||||
|
class R2,A2,R4,A4,R5,A5 amber
|
||||||
|
class R3,A3 red
|
||||||
|
class R6,A6 teal
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Source document: `docs/security-posture-workflow.md`*
|
||||||
175
docs/security-posture-workflow-lucidchart.md
Normal file
175
docs/security-posture-workflow-lucidchart.md
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# Lucidchart Import — Raw Mermaid Code
|
||||||
|
|
||||||
|
Lucidchart expects raw Mermaid syntax only — no markdown headings or prose.
|
||||||
|
Paste each diagram separately: Insert → Diagram as Code → Mermaid → paste → Generate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DIAGRAM 1 — Host Finding Review Workflow
|
||||||
|
|
||||||
|
Paste everything between the triple-backtick fences below:
|
||||||
|
|
||||||
|
```
|
||||||
|
flowchart TD
|
||||||
|
START([Open Reporting Page]) --> SYNC
|
||||||
|
|
||||||
|
SYNC["① Sync & Sort<br/>Click Sync · Sort Due Date ascending"]
|
||||||
|
SYNC --> DUE{Overdue<br/>findings?}
|
||||||
|
DUE -->|Yes — start here| HOST
|
||||||
|
DUE -->|No — start with amber| HOST
|
||||||
|
|
||||||
|
HOST["② Identify the Host<br/>Verify IP in IPControl / Infoblox"]
|
||||||
|
HOST --> CORRECT{Hostname<br/>correct?}
|
||||||
|
CORRECT -->|No| EDIT["Inline-edit Host / DNS cell<br/>Amber dot marks the override"]
|
||||||
|
EDIT --> OWN
|
||||||
|
CORRECT -->|Yes| OWN
|
||||||
|
|
||||||
|
OWN["③ Identify Asset Ownership<br/>Check BU column"]
|
||||||
|
OWN --> BU{Our BU?}
|
||||||
|
BU -->|"NTS-AEO-STEAM or ACCESS-ENG"| CVE
|
||||||
|
BU -->|"Other BU or blank"| CARD["Add to CARD Queue<br/>checkbox → CARD → Add to Queue"]
|
||||||
|
CARD --> CARD2([Process in dedicated CARD session])
|
||||||
|
|
||||||
|
CVE["④ Review CVEs in the Finding<br/>Up to 2 shown · hover badge for more"]
|
||||||
|
CVE --> DBCHECK{CVE in<br/>database?}
|
||||||
|
DBCHECK -->|No| ADDCVE["Create CVE entry on Home page<br/>NVD auto-fill populates details"]
|
||||||
|
ADDCVE --> RESEARCH
|
||||||
|
DBCHECK -->|Yes — review existing notes/docs| RESEARCH
|
||||||
|
|
||||||
|
RESEARCH["Research CVE<br/>Vendor advisory · Cisco Bug Search<br/>Juniper PSN · Support ticket"]
|
||||||
|
RESEARCH --> ACTION
|
||||||
|
|
||||||
|
ACTION["⑤ Determine Required Action"]
|
||||||
|
ACTION --> PATH{What does<br/>research show?}
|
||||||
|
|
||||||
|
PATH -->|"Patch available — FW / SW update"| PA
|
||||||
|
PATH -->|"Fix is config change only"| PB
|
||||||
|
PATH -->|"Not applicable to platform / version"| PC
|
||||||
|
PATH -->|"Cannot patch — vendor / EOL / business"| PD
|
||||||
|
|
||||||
|
PA["PATH A — Remediation<br/>Firmware or Software Upgrade"]
|
||||||
|
PA --> PA1["Plan & schedule upgrade<br/>Add note to finding row"]
|
||||||
|
PA1 --> PA2(["Finding drops off after<br/>next Ivanti scan ✓"])
|
||||||
|
|
||||||
|
PB["PATH B — Remediation<br/>Configuration Change"]
|
||||||
|
PB --> PB1["checkbox → Vendor → Archer<br/>Add to Queue"]
|
||||||
|
PB1 --> PB2["Open Archer EXC ticket<br/>in dedicated session"]
|
||||||
|
PB2 --> PB3(["Enter EXC-XXXXX<br/>in finding Notes cell ✓"])
|
||||||
|
|
||||||
|
PC["PATH C — False Positive"]
|
||||||
|
PC --> PC1["Take device screenshot<br/>Hostname · IP · SW version"]
|
||||||
|
PC1 --> PC2["Obtain vendor documentation<br/>advisory / email / support ticket"]
|
||||||
|
PC2 --> PC3["Upload evidence to CVE database<br/>Home page → CVE row → Upload"]
|
||||||
|
PC3 --> PC4["checkbox → Vendor → FP<br/>Add to Queue"]
|
||||||
|
PC4 --> PC5(["Submit FP workflow in Ivanti<br/>in dedicated session ✓"])
|
||||||
|
|
||||||
|
PD["PATH D — Risk Acceptance"]
|
||||||
|
PD --> PD1["Take device screenshot<br/>Collect version info"]
|
||||||
|
PD1 --> PD2{Vendor comms<br/>needed?}
|
||||||
|
PD2 -->|Yes| PD3["Open vendor support ticket<br/>Request patch timeline / mitigations"]
|
||||||
|
PD3 --> PD4
|
||||||
|
PD2 -->|No| PD4["checkbox → Vendor → Archer<br/>Add to Queue"]
|
||||||
|
PD4 --> PD5["Open Archer EXC ticket<br/>in dedicated session"]
|
||||||
|
PD5 --> PD6(["Enter EXC-XXXXX<br/>in finding Notes cell ✓"])
|
||||||
|
|
||||||
|
classDef step fill:#1e3a5f,stroke:#0ea5e9,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef decision fill:#1a2e1a,stroke:#10b981,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef pathA fill:#14391f,stroke:#10b981,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef pathB fill:#2d1f14,stroke:#f59e0b,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef pathC fill:#2d1414,stroke:#ef4444,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef pathD fill:#1a1430,stroke:#8b5cf6,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef card fill:#1a2e1a,stroke:#10b981,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef done fill:#0f172a,stroke:#475569,stroke-width:1.5px,color:#64748b
|
||||||
|
|
||||||
|
class SYNC,HOST,OWN,CVE,RESEARCH,ACTION step
|
||||||
|
class DUE,CORRECT,BU,DBCHECK,PATH decision
|
||||||
|
class PA,PA1,PA2 pathA
|
||||||
|
class PB,PB1,PB2,PB3 pathB
|
||||||
|
class PC,PC1,PC2,PC3,PC4,PC5 pathC
|
||||||
|
class PD,PD1,PD2,PD3,PD4,PD5,PD6 pathD
|
||||||
|
class CARD,CARD2 card
|
||||||
|
class EDIT done
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DIAGRAM 2 — FP Workflow Badge Status Decision Tree
|
||||||
|
|
||||||
|
```
|
||||||
|
flowchart LR
|
||||||
|
A([Finding in Reporting Page]) --> B{"Check Workflow column"}
|
||||||
|
|
||||||
|
B -->|No badge| C["UNTRIAGED<br/>No action on record"]
|
||||||
|
C --> C1(["Follow the Step 1-5 triage workflow"])
|
||||||
|
|
||||||
|
B -->|Blue - Requested| D["IN FLIGHT<br/>FP submitted · awaiting approval"]
|
||||||
|
D --> D1{"SLA window<br/>approaching?"}
|
||||||
|
D1 -->|No| D2(["Monitor — no action yet"])
|
||||||
|
D1 -->|Yes| D3(["Follow up with the approver"])
|
||||||
|
|
||||||
|
B -->|Amber - Reworked| E["NEEDS REVISION<br/>Reviewer returned the ticket"]
|
||||||
|
E --> E1["Open ticket in Ivanti<br/>Review feedback"]
|
||||||
|
E1 --> E2(["Update justification and resubmit"])
|
||||||
|
|
||||||
|
B -->|Amber - Actionable| F["NEEDS RESPONSE<br/>Ticket flagged for team action"]
|
||||||
|
F --> F1(["Open ticket in Ivanti<br/>Respond to the request"])
|
||||||
|
|
||||||
|
B -->|Red - Expired| G["EXCEPTION LAPSED<br/>Finding has re-opened"]
|
||||||
|
G --> G1(["Submit a new FP request in Ivanti<br/>Reference previous ticket"])
|
||||||
|
|
||||||
|
B -->|Red - Rejected| H["CONFIRMED VULNERABILITY<br/>Security team denied the FP"]
|
||||||
|
H --> H1(["Remediate the vulnerability<br/>Do not resubmit FP without new evidence"])
|
||||||
|
|
||||||
|
classDef trigger fill:#0f172a,stroke:#0ea5e9,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef blue fill:#1e3a5f,stroke:#0ea5e9,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef amber fill:#2d2014,stroke:#f59e0b,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef red fill:#2d1414,stroke:#ef4444,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef none fill:#1a1a2e,stroke:#475569,stroke-width:1.5px,color:#94a3b8
|
||||||
|
classDef done fill:#0f172a,stroke:#334155,stroke-width:1px,color:#64748b
|
||||||
|
|
||||||
|
class A,B trigger
|
||||||
|
class D,D1,D2,D3 blue
|
||||||
|
class E,E1,E2,F,F1 amber
|
||||||
|
class G,G1,H,H1 red
|
||||||
|
class C,C1 none
|
||||||
|
class D2,D3,E2,F1,G1,H1 done
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DIAGRAM 3 — Action Decision Matrix
|
||||||
|
|
||||||
|
```
|
||||||
|
flowchart LR
|
||||||
|
START(["Research complete — Step 4 done"]) --> Q{"What is the<br/>remediation path?"}
|
||||||
|
|
||||||
|
Q --> R1["Firmware or software update available"]
|
||||||
|
R1 --> A1(["No ticket needed<br/>Schedule upgrade · Add note to finding"])
|
||||||
|
|
||||||
|
Q --> R2["Fix is a configuration change only"]
|
||||||
|
R2 --> A2(["Archer EXC ticket required<br/>Stage as Archer in Queue"])
|
||||||
|
|
||||||
|
Q --> R3["Not applicable to this platform / version"]
|
||||||
|
R3 --> A3(["FP workflow in Ivanti<br/>Evidence in CVE database"])
|
||||||
|
|
||||||
|
Q --> R4["Patch not yet available from vendor"]
|
||||||
|
R4 --> A4(["Archer EXC ticket<br/>Renew when patch ships"])
|
||||||
|
|
||||||
|
Q --> R5["Device is EOL / EOS or business constraint"]
|
||||||
|
R5 --> A5(["Archer ticket with mitigation steps<br/>and remediation plan"])
|
||||||
|
|
||||||
|
Q --> R6["Asset not owned by our BU"]
|
||||||
|
R6 --> A6(["CARD queue — CARD disposition process"])
|
||||||
|
|
||||||
|
classDef q fill:#1e3a5f,stroke:#0ea5e9,stroke-width:2px,color:#e2e8f0
|
||||||
|
classDef green fill:#14391f,stroke:#10b981,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef amber fill:#2d2014,stroke:#f59e0b,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef red fill:#2d1414,stroke:#ef4444,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
classDef teal fill:#0f2d2d,stroke:#14b8a6,stroke-width:1.5px,color:#e2e8f0
|
||||||
|
|
||||||
|
class START,Q q
|
||||||
|
class R1,A1 green
|
||||||
|
class R2,A2,R4,A4,R5,A5 amber
|
||||||
|
class R3,A3 red
|
||||||
|
class R6,A6 teal
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user