Files
cve-dashboard/.kiro/steering/tech.md
Jordan Ramos a95fd03f5e Rebrand STEAM → AEGIS, fix BU drift checker previous_bu bug
- Replace all STEAM branding with AEGIS (Advanced Engineering Group
  Intelligence System) across login, header, nav drawer, manifest, and
  browser title
- Add shield logo to login page, main header, and nav drawer
- Fix BU drift checker recording incorrect previous_bu values by
  building a previousBuMap snapshot BEFORE the upsert/delete cycle
  instead of querying the DB after rows are already gone
- Clean 526 bogus BU history entries generated by the broken logic
- Add docs and scripts from prior session
2026-06-17 14:40:38 -06:00

7.5 KiB

Tech Stack & Build System

Stack

Layer Technology
Backend Node.js 18+, Express 5
Database PostgreSQL (via pg pool in backend/db.js)
Auth bcryptjs, cookie-based sessions (httpOnly, 24h expiry)
File uploads Multer 2 (10MB limit)
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
Diagrams mermaid

Architecture: Single-Port Serving

Express on port 3001 serves both the API and the production frontend build:

  • API routes: /api/* — handled by Express route handlers
  • Frontend: everything else — served as static files from frontend/build/

There is no separate frontend server in production. The React dev server (npm start on port 3000) is only for local development with hot-reload. In production and on the dev server, you must run npm run build in frontend/ after any frontend code change, then restart the backend.

After editing frontend source files:

cd frontend && npm run build    # Compile new bundle into frontend/build/
# Then restart backend (or it will serve the new static files on next request)

The CI/CD pipeline handles this automatically — build-frontend stage runs before deploy.

Common Commands

Backend

cd backend
node setup.js          # Initialize DB, tables, indexes, default admin user
node server.js         # Start backend on port 3001 (serves API + frontend build)

Frontend

cd frontend
npm install            # Install dependencies
npm run build          # Production build → frontend/build/ (REQUIRED after code changes)
npm start              # Dev server on port 3000 (local dev only, NOT used in production)
npm test               # Run tests (react-scripts test)

Both servers (from project root)

./start-servers.sh     # Start backend + frontend in background
./stop-servers.sh      # Stop all servers

Database Migrations (run from backend/)

node migrations/run-all.js    # Runs all migrations in order (idempotent)

Python Scripts (from backend/scripts/)

# Compliance xlsx parsing (called automatically by upload flow)
python3 parse_compliance_xlsx.py <file>

# Bulk notes import
python3 import_notes_from_csv.py input.csv --dry-run
python3 import_notes_from_csv.py input.csv

Python dependencies: pandas>=2.0.0, openpyxl>=3.0.0 (install via apt or venv).

Environment Configuration

  • backend/.env — PORT, CORS_ORIGINS, SESSION_SECRET, NVD_API_KEY, Ivanti API credentials, CARD API credentials
  • frontend/.env — REACT_APP_API_BASE, REACT_APP_API_HOST
  • Both .env files are gitignored; see .env.example files for templates.
  • React env vars are baked in at build time — you must rebuild (npm run build) after changing them.

Key Backend Env Vars

Variable Purpose
IVANTI_API_KEY RiskSense platform API key
IVANTI_CLIENT_ID RiskSense client ID (default: 1550)
IVANTI_BU_FILTER Comma-separated BU teams to sync findings for (default: NTS-AEO-ACCESS-ENG,NTS-AEO-STEAM)
IVANTI_FIRST_NAME / IVANTI_LAST_NAME Fallback Ivanti identity for workflow sync (used only if no per-user identities configured)
CARD_API_URL CARD API base URL (e.g., https://card.charter.com)
CARD_API_USER / CARD_API_PASS CARD OAuth credentials for Bearer token acquisition
CARD_SKIP_TLS Set to true to skip TLS verification (for SSL inspection proxies)
DATABASE_URL PostgreSQL connection string

CARD API and Ivanti Integration Details

See .kiro/steering/integrations.md for full API contracts, response shapes, and quirks for CARD, Ivanti, Atlas, and Jira.

Ivanti Findings IPv6 Handling

Some Ivanti findings have no IPv4 address. The sync captures fallback addresses:

  • qualys_ipv6 — from hostAdditionalDetails[].["IPv6 Address"] (resolves in CARD)
  • primary_ipv6 — from assetCustomAttributes['1550_host_6'][0] (may not resolve in CARD)

Display priority in the UI: IPv4 > Qualys IPv6 (amber "Q" badge) > Primary IPv6 (indigo "v6" badge)

Code Style & Lint Rules

Unused Variables

The frontend ESLint config enforces no-unused-vars as a warning. The CI pipeline fails if warnings exceed 25. To avoid lint failures:

  • Prefix intentionally-unused variables with _ — this suppresses the warning. The varsIgnorePattern: "^_" and argsIgnorePattern: "^_" rules are configured in frontend/package.json.
  • Common patterns:
    • const [_unused, setFoo] = useState(...) — destructured value you don't need
    • const _legacyRef = useRef(...) — kept for future use
    • function handler(_event) { ... } — required parameter signature but unused
  • Do not leave variables unprefixed if unused. Either use them, remove them, or prefix with _.
  • This applies to all frontend code written by the agent.

Backend

No ESLint is configured for backend — the pipeline uses node -c syntax checking only. Keep code clean but there is no automated unused-var enforcement on the backend side.

Ports

Environment URL Notes
Production http://71.85.90.6:3001 Express serves API + static frontend build
Staging http://71.85.90.9:3100 Auto-deploy on master push
Local dev (frontend only) http://localhost:3000 React dev server with hot-reload, proxies API to :3001

Secure Context Constraints

All environments serve over plain HTTP (not HTTPS). This means browser APIs that require a secure context are not available in production or staging:

  • navigator.clipboard (Clipboard API) — use document.execCommand('copy') with a hidden textarea instead
  • navigator.share (Web Share API)
  • crypto.subtle (Web Crypto API)
  • navigator.credentials (Credential Management API)
  • Service Workers and Push Notifications

When writing frontend code that needs clipboard, sharing, or crypto functionality, always use the non-secure fallback pattern. Do not use navigator.clipboard.writeText() or similar secure-context APIs.

CI/CD Pipeline

Infrastructure

Role Host Notes
GitLab instance steam-gitlab.charterlab.com Self-hosted GitLab
CI Runner (LXC 108) 71.85.90.8 Docker executor, Runner #6, project-locked
Staging target 71.85.90.9 Auto-deploy on master, port 3100
Production target 71.85.90.6 Manual deploy trigger, port 3001

Executor: Docker

The pipeline uses Docker executor on Runner #6. Jobs run in isolated containers:

  • Install / Lint / Test / Build stages: node:18 image
  • Deploy stages: alpine:latest image (installs openssh-client and rsync at runtime)

Deploy jobs SSH from inside the Alpine container to the target hosts using a base64-encoded $SSH_PRIVATE_KEY stored as a GitLab CI/CD variable.

CI/CD Variables (project-level)

These are set in GitLab → Settings → CI/CD → Variables:

Variable Purpose
DATABASE_URL PostgreSQL connection string for backend integration tests
SSH_PRIVATE_KEY Base64-encoded private key for deploy SSH access
GITLAB_PAT Project access token for issue comments and release creation

Pipeline file

The pipeline is defined in .gitlab-ci.yml at the project root. Stages: install → lint → test → build → deploy → verify.