# Changelog

All notable changes to the STEAM Security Dashboard are documented in this file.

Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

---

## [v2.4.0] — 2026-06-24

### Added

- **Backend team enforcement** — `requireTeam()` middleware enforces team-scoped data access at the API level. Non-admin users can only access findings, compliance data, CARD assets, and Atlas metrics for their assigned BU teams. Users with no team assignment receive 403.
- **Page visibility by group** — centralized matrix in `config/pageVisibility.js` controls which pages each user group can access. Read_Only sees Home + Knowledge Base only. Leadership adds Triage, Compliance, CCP Metrics, and Exports. Standard_User adds Jira and Archer Templates. Admin sees all.
- **View As (impersonation)** — Admin users can temporarily view the app as another user via the eye icon in User Management. An amber banner shows the impersonated identity with an Exit button. Exercises real enforcement code paths for permission verification.
- **Homepage UX improvements** — drag-and-drop document upload, recent activity feed with tabbed sidebar layout, extracted components for cleaner architecture.
- **TLS/HTTPS support** — auto-detection of cert/key files enables HTTPS serving without configuration changes.
- **Granite Loader on Compliance page** — CARD enrichment with pagination for compliance-driven Granite sheet generation.

### Changed

- **Team name mapping centralized** — `helpers/teams.js` now exports `TEAM_TO_IVANTI`, `IVANTI_TO_TEAM`, `teamToIvanti()`, and `ivantiToTeam()` for consistent mapping between short names and Ivanti BU identifiers.
- **Atlas and Archive routes** — now use `requireTeam()` instead of client-provided `?teams=` query parameter for team scoping.
- **Jira and Archer Template routes** — now enforce `requireGroup('Admin', 'Standard_User')` at router level for page-level access control.
- **Activity feed** — impersonation events (`impersonate_start`, `impersonate_stop`) are hidden from non-Admin users.
- **NavDrawer** — uses centralized `canAccessPage()` instead of inline `requiredGroups` properties.
- **App.js** — generic route guard via `setCurrentPage` replaces per-page `isInGroup()` checks; localStorage validation ensures persisted page is accessible.

### Fixed

- **BulkHideToolbar** — no longer detaches from viewport when scrolling on Reporting page.
- **BU drift checker** — skips history entries when `previous_bu` is unknown.
- **Compliance upload limits** — raised to 100MB to accommodate larger xlsx files.

---

## [2.3.0] — 2026-06-16

### Added

- **BU reassignment detail view** — click the "BU reassignment" count in the anomaly banner to see which specific findings moved and from/to which team
- **Atlas sync scoped to active teams** — Atlas sync now respects BU scope and defaults to managed BUs, preventing cache pollution from unrelated teams
- **Atlas known host distinction** — badge only renders for hosts Atlas actively tracks, suppressing noise from BUs not covered by Atlas (e.g., ACCESS-OPS)
- **Per-user Ivanti identity** — FP workflow views filtered by individual Ivanti first/last name for personalized queue
- **Searchable dropdowns for Granite Loader** — team, operation type, and status columns now use filterable select inputs
- **IPv6 fallback display** — findings without IPv4 show Qualys IPv6 (amber Q badge) or primary IPv6 (indigo v6 badge)
- **Remediate workflow type** — new workflow option in Ivanti Queue with remediation notes appended to Jira tickets
- **DECOM workflow type** — added to RedirectModal workflow options
- **View in CARD button** — added to tooltip and action modal for direct CARD web UI navigation
- **CARD asset-search by Host ID** — faster lookup path for enrichment operations
- **Per-metric compliance views** — replaced cross-metric aggregates with per-metric summary cards
- **Non-metric category filters** on compliance page
- **Ivanti Findings Data Guide** — Knowledge Base article explaining common data patterns (missing CVEs, BU reassignment, Atlas badges, etc.)
- **Markdown table rendering** in Knowledge Base viewer (remark-gfm support)
- **In-app notifications** table and infrastructure

### Fixed

- **Drift checker re-classifying same findings every sync** — archived findings were never removed from ivanti_findings, causing ~500 false re-classifications per sync. Now properly cleaned up after archive detection
- **Atlas Coverage tab not responding to scope changes** — metrics and status endpoints now filter by active teams and re-fetch on scope switch
- **Knowledge Base content/download failing for relative file paths** — sendFile now resolves paths correctly
- **remark-gfm compatibility** — upgraded to v4 for react-markdown v10 (was causing blank KB viewer)
- **SearchableSelect** — only opens on focus, closes properly on blur/select
- **Clipboard copy on HTTP** — use execCommand fallback for non-secure contexts
- **Empty description in single-item Jira modal** on ReportingPage
- **CARD enrich for items without IP** — uses host_id lookup as fallback
- **update_token error handling** — shows CARD link for assets that can't be actioned via API
- **Decom workflow migration** — includes Remediate in state check constraint

### Changed

- Atlas sync defaults to `IVANTI_MANAGED_BUS` when no scope is specified instead of syncing all BUs
- BU change history API accepts `since` and `limit` query params for scoped queries
- Anomaly banner uses 60-minute lookback window to capture drift checker records
- Archive activity chart should now show near-zero on normal syncs (only genuinely new disappearances)

---

## [2.2.0] — 2026-06-04

### Features

- **Group by Host toggle** on the Ivanti findings table — collapses duplicate assets (same hostname + IP) with multiple finding IDs into expandable host rows. Hosts with only one finding remain as flat rows. Toggle between grouped and flat views from the toolbar.
- **CARD ownership tooltip on IP hover** — hover over any IP address in the findings table to see CARD asset ownership data (confirmed/unconfirmed/candidate teams) in an interactive tooltip. Results cached per session for instant re-display.
- **CARD direct action modal** — click "Actions" in the CARD tooltip to open a full confirm/decline/redirect modal that works directly against the CARD API without needing a queue item.
- **Inline view panel** in the Archer Template Manager with per-section copy buttons
- **Queue item redirect in place** — pending queue items can now be redirected without duplicating

### Bug Fixes

- Improve CARD decline error diagnostics and prevent accidental modal dismiss
- CARD teams fetch retries silently up to 3x on failure with increasing delay
- Redirect dropdowns show owner-data teams as fallback when the full teams API fails
- CARD tooltip uses quick mode (CTEC suffix only, 15s timeout) to avoid multi-minute waits
- Timeouts (504) are not cached — re-hover will retry the lookup

---

## [2.1.0] — 2026-06-06

### Features

- **Archer Template Library** — new template management system for Archer Risk Acceptance forms. Store static content (Environment Overview, Segmentation, Mitigating Controls) organized by Vendor > Platform > Model. Full CRUD with clone, search/filter, and per-section copy-to-clipboard. Accessible from the nav drawer (Template Mgr) and integrated into the Ivanti Queue for Archer workflow items.
- **Estimated resolution date per metric** — the compliance asset sidebar now shows each noncompliant metric's estimated resolution date at the top of its section, in `YYYY-MM-DD` format, with placeholders for metrics that have no date set or an invalid date (closes #20)
- **CARD Action Modal** with full owner context
- **Granite Loader Sheet generator** with CARD enrichment, plus a Loader Sheet button on the Reporting page queue panel
- **Vendor-specific issue type dropdown** for Jira ticket creation, with all vendor project keys
- **LIVE and LAST REPORT badges** on the VCL compliance page
- **Collapsible sections** on the Ivanti Queue page and side panel

### Bug Fixes

- Fix remediation plan and resolution date missing from the compliance table; format `resolution_date` as `YYYY-MM-DD`
- Improve CARD action error messages and default loader columns
- Fix CARD production timeout by forcing IPv4 (`dns.setDefaultResultOrder('ipv4first')`)
- Add IP address validation to CARD confirm/decline/redirect actions
- Auto-resolve bare IP to CARD asset ID with suffix lookup
- Increase CARD API timeout from 15s to 30s
- Rewrite CARD enrich-batch to use the team assets endpoint for full data

---

## [2.0.0] — 2026-05-26

### Breaking Changes

- **PostgreSQL migration** — database engine switched from SQLite to PostgreSQL. Requires running `deploy-postgres.sh`, data migration, and `DATABASE_URL` env var. SQLite is no longer supported.
- **Multi-BU tenancy** — data is now scoped per business unit with per-user team assignments. Replaces the previous binary scope toggle.
- **Raw Jira status display** — removed Open/In Progress/Closed status mapping; shows the actual Jira status field everywhere.

### Features

- **Jira integration overhaul**
  - Flexible Jira ticket creation — CVE/Vendor fields optional, source context tracking
  - Multi-item Jira ticket creation from Ivanti Queue (consolidation modal)
  - Issue type dropdown and Save to Dashboard from Jira lookup
  - Success toast after consolidated ticket creation
  - Improved Jira lookup error messages
- **CCP Metrics page** — multi-vertical VCL upload and cross-org compliance reporting
  - Metric-first hierarchy restructure with Jira cross-project sync
  - 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
  - Per-metric remediation plans
  - VCL metric calculations guide
- **Exports page** — Jira Tickets, CCP Metrics, and Remediation Status export cards
- **VCL compliance reporting** — exec report page, device metadata fields, bulk upload
- **Data management panel** — delete vertical, rollback upload, and reset all
- **In-app notification system** — replaces Webex bot integration with native notifications
- **Remediation plan and resolution date history tracking**
- **FP submissions cleanup** — auto-clear approved, dismiss rejected, collapsible section
- **Re-queue findings** from rejected FP submissions
- **DECOM workflow type** — auto-note/hide on decom, show CVEs on CARD queue items
- **Interactive configuration wizard** for deployment setup
- **Unified setup script** (`configure.js`) merging deploy + config wizard
- **Per-BU trend lines** in Ivanti counts history chart
- **Multi-select BU picker** replacing binary scope toggle
- **Configurable IVANTI_MANAGED_BUS** env var for multi-tenant drift classification
- **Pipeline-to-issue traceability** via `after_script` comments in CI/CD
- **CI/CD pipeline** with health endpoint and automated deploy stages
- **Docker Compose** and `deploy-postgres.sh` for production cutover
- **Systemd service scripts** for start/stop management
- **VCL vertical metadata** — inline-editable team fields on compliance routes

### Bug Fixes

- Fix Clear Completed button failing on queue items with Jira ticket links (FK violation)
- Fix status badge background making text invisible
- Fix calendar SLA dates not highlighting after Postgres migration
- Fix document View link using localhost instead of relative URL
- Validate library doc file types before sending to Ivanti API
- Improve FP workflow error messages — include Ivanti API response body
- Fix forecast chart bar order and snapshot month derivation
- Fix forecast deduplication for multi-vertical metrics
- Fix CCP Metrics page crash for non-Admin users
- Fix CCP Metrics crash when donut chart has zero non-compliant devices
- Fix duplicate failing metrics on same asset across compliance endpoints
- Fix duplicate chart entries on compliance page when multiple verticals share a report_date
- Fix requeue inserting Postgres array literal instead of JSON into `cves_json`
- Fix todo queue crash on malformed `cves_json` data
- Fix AEO compliance page not showing metric health cards on dev
- Fix double-counting in VCL multi-vertical stats — use only `ALL:` rollup rows
- Fix compliance stats to use Summary sheet data instead of item counts
- Fix route mount order: `vcl-multi` must precede general compliance router
- Fix requeue: fallback to `finding_ids_json` when queue items are deleted or absent
- Sync FP submission `lifecycle_status` from Ivanti `currentState` on fetch
- Fix History tab crash: coerce Ivanti note fields to strings before rendering
- Fix archive bar chart: `fmtDate` now handles ISO datetime strings from PostgreSQL
- Fix Ivanti panel bugs: Invalid Date, wrong workflow count, crash on archive click
- Fix BU drift checker: derive `EXPECTED_BUS` from `IVANTI_BU_FILTER` env var
- Fix null `bu_teams` in postgres migration, add retry logic to deploy script
- Fix missing `created_by` column in `archer_tickets` table
- Fix FP workflow counts donut scoped by BU
- Fix `dotenv` loading in `db.js` so `DATABASE_URL` is available on import

### Maintenance

- Track `package-lock.json` files for deterministic CI installs
- Remove unused imports to satisfy ESLint thresholds
- CI pipeline fixes: dependency installation, lint thresholds, test isolation
- Auto-run migrations in pipeline
- Strengthen migration registration hook
- Documentation updates for PostgreSQL migration, systemd scripts, and reference manual

---

## [1.0.0] — 2026-05-01

Initial release of the STEAM Security Dashboard.

