Files
Christopher Fahlin bd73dc781b docs: update README and CLAUDE.md for current feature set
Add Grype/Snyk to supported formats, settings route, filter bar
component, accent theming. Fix dark mode description.
2026-05-13 21:22:46 -07:00

3.3 KiB

Bulwark

Security dashboard for ingesting, viewing, and triaging vulnerability findings from CI/CD scan artifacts. Supports Trivy, SARIF, and CycloneDX report formats.

Built with Phoenix 1.8, LiveView 1.1, PostgreSQL, and Oban.

Features

  • Multi-format ingestion — Upload Trivy JSON, SARIF, CycloneDX, Grype, and Snyk reports. Auto-detects format and tool.
  • Async processing — Oban workers parse artifacts in the background with retry support.
  • Real-time updates — PubSub broadcasts push scan status and finding changes to all connected clients.
  • Triage workflow — Acknowledge, resolve, or mark findings as false positives inline.
  • Flop-powered tables — Sortable, filterable, paginated tables across all list views with cmd+K filter bars and quick-filter pills.
  • Dark-mode SOC aesthetic — Zinc palette with optional accent theming. Inter for UI, JetBrains Mono for technical data.

Getting Started

Prerequisites

  • Elixir ~> 1.15 and Erlang/OTP 26+
  • PostgreSQL 14+ (or use the included Docker Compose)

Setup

# Clone the repository
git clone <repo-url> && cd bulwark

# Start PostgreSQL
docker compose up -d

# Install dependencies, create database, and run migrations
mix setup

# Start the development server
mix phx.server

Visit localhost:4000.

Running Tests

mix test                         # All tests
mix test test/path_test.exs      # Single file
mix test test/path_test.exs:42   # Single test by line

Pre-commit Check

mix precommit

Runs compile --warnings-as-errors, deps.unlock --check-unused, format --check-formatted, and test.

Architecture

lib/
├── bulwark/           # Domain layer
│   ├── security.ex          # Security context — CRUD, queries, triage
│   ├── security/            # Schemas: Scan, Asset, Vulnerability, Finding
│   ├── ingestion/           # Pipeline: Detector, ParseJob (Oban), Parsers
│   └── repo.ex
└── bulwark_web/       # Web layer
    ├── components/          # CoreComponents, Layouts (sidebar shell)
    ├── live/                # LiveViews for each route
    ├── router.ex
    └── endpoint.ex

Bounded Contexts

Context Purpose
Bulwark.Security Domain CRUD, Flop queries, upserts, triage with PubSub
Bulwark.Ingestion Format detection, parsing, Oban job orchestration

Ingestion Pipeline

Upload → Scan record (pending) → Oban ParseJob → Detector identifies tool/format → Parser normalizes findings → Assets/Vulnerabilities upserted → Findings persisted → PubSub broadcast → LiveView updates.

Routes

Path View Purpose
/ DashboardLive KPI overview
/scans ScanLive.Index Scan list + upload
/scans/:id ScanLive.Show Scan detail + findings
/vulnerabilities VulnerabilityLive.Index Vulnerability list
/vulnerabilities/:id VulnerabilityLive.Show Vuln detail + references
/findings FindingLive.Index Finding list + triage
/assets AssetLive.Index Asset inventory
/assets/:id AssetLive.Show Asset detail + findings
/settings SettingsLive Accent theming preferences

License

See LICENSE for details.