The DELETE /completed endpoint failed with a FK violation when completed
queue items had associated rows in jira_ticket_queue_items. Replaced the
bare DELETE query with a transaction that removes junction table references
before deleting the queue items themselves.
Transaction sequence: BEGIN → SELECT completed IDs → DELETE junction rows →
DELETE queue items → COMMIT, with ROLLBACK on error and client release in
finally block.
Source DATABASE_URL from /home/cve-dashboard/backend/.env in test-backend job
so the integration test can connect to the local Postgres instance.
The test now skips gracefully via describe.skip when DATABASE_URL is unavailable
(defensive fallback), but with the env sourced it will run and validate migrations.
Per-metric remediation plan scoping (GitLab issue #19):
- Add metric_id column to compliance_item_history table (migration)
- Extend PATCH /items/:hostname/metadata to accept metric_id/metric_ids
for targeting specific metrics instead of all active items
- Add MetricChipSelector UI in detail panel for choosing which metrics
to apply resolution_date and remediation_plan changes to
- Display per-metric labels (MetricChip or 'All metrics') on history entries
- Backward compatible: omitting metric_ids preserves hostname-level behavior
CI/CD pipeline improvements:
- Add migration idempotency integration test (runs against real Postgres)
- Add post-deploy smoke tests for compliance and VCL endpoints
- Bump lint --max-warnings from 10 to 25
- Configure varsIgnorePattern for _ prefix convention on unused vars
Closes#19
Select multiple queue items and create a single consolidated Jira ticket
with aggregated summary and description. Adds multi-select mode with
checkboxes, floating action bar, consolidation modal, and junction table
to track which queue items contributed to each ticket.
- Migration: jira_ticket_queue_items junction table
- POST /api/jira-tickets/:id/queue-items endpoint
- GET /api/ivanti/todo-queue/ticket-links endpoint
- ConsolidationModal component with aggregation logic
- IvantiTodoQueuePage with selection mode and ticket link badges
- Pure utility functions for summary/description generation
- 34 tests passing (backend + frontend)
The project filter was intentionally removed from searchIssuesByKeys() to
fix cross-project ticket sync. Update the property test to no longer assert
the presence of 'project =' in the generated JQL.
Deduplicate (hostname, metric_id) rows across verticals using DISTINCT ON in
GET /items, GET /items/:hostname, GET /vcl/stats (heavy-hitters + forecast),
GET /mttr, and persistUpload() snapshot block. Add defensive groupByHostname
Set and hostname_status CTE for snapshot classification.
Includes 38 property-based tests (11 exploration + 27 preservation) covering
all six affected sites.
Closes#13
Aggregate /trends, /top-recurring, /category-trend by report_date instead of
per-upload row. Add sibling-upload disclosure to /summary. Filter persistUpload
snapshot query by the upload's vertical to prevent cross-vertical contamination.
Fixes GitLab #12 (reported by nkapur — STEAM active findings chart showed 3
entries for 5/11 after uploading three vertical data sets for that date).
Includes 30 property-based tests covering bug condition and preservation.
Single-file Node.js CLI that orchestrates the full setup lifecycle:
- Interactive env var configuration with validation and smart defaults
- Postgres provisioning via Docker Compose with readiness polling
- Schema initialization (psql with docker exec fallback)
- npm dependency installation with 120s timeout
- Optional SQLite-to-Postgres data migration with retry logic
- Frontend build with smart skip on reconfiguration
Includes 84 tests: 50 property-based (fast-check) covering 19 correctness
properties, and 34 integration tests for filesystem and parsing flows.
New table compliance_item_history stores an append-only audit trail of
changes to resolution_date and remediation_plan. The current values remain
on compliance_items for fast VCL reporting queries (no double-counting).
Backend:
- Migration: creates compliance_item_history with indexes
- PATCH /items/:hostname/metadata: records old→new in history before updating,
accepts optional change_reason field (max 500 chars)
- GET /items/:hostname: returns history array (last 10 entries, newest first)
- POST /vcl/bulk-commit: records history for each changed field per hostname
Frontend:
- ComplianceDetailPanel: added change reason input below Save button
- Added Change History section showing field changes with timestamps,
usernames, old→new values, and reasons
- Re-fetches detail after save to show updated history immediately
Tests updated to match new transaction-based PATCH flow.
PostgreSQL + Ivanti API enrichment can return non-string values
(objects/arrays) for currentStateUserNotes and similar fields.
React crashes silently (blank page, no console error) when trying
to render non-string values as children. Same root cause pattern
as Bug 3 in ivanti-panel-bugs-2026-05-12.
Added safeText() wrapper that coerces any non-string truthy value
to a JSON string before rendering in the History tab notes section.
Also fixed flaky property test: fc.date() could generate invalid
dates causing RangeError on .toISOString(). Added .filter() guard
and explicit UTC date bounds.
- Add bu_teams column to users table (migration + fresh schema)
- Create shared KNOWN_TEAMS constant and validateTeams helper
- Expose user teams in auth middleware, login, and /me responses
- Add bu_teams CRUD to user management routes with audit logging
- Make Ivanti FINDINGS_FILTERS configurable via IVANTI_BU_FILTER env var
- Add query-time team filtering to GET /findings and /findings/counts
- Update AuthContext with teams helpers and admin scope toggle
- Create AdminScopeToggle component (My Teams / All BUs)
- Scope ReportingPage findings fetch by user teams
- Scope CompliancePage team selector by user teams
- Scope ExportsPage findings exports by user teams
- Add BU teams multi-select to UserManagement create/edit forms
- Display team badges in user list table