Skip to content

geek-kb/trivy-ui

Repository files navigation

Trivy UI

A modern, secure, and lightweight web UI for browsing, filtering, and visualizing Trivy vulnerability reports.


✨ Features

  • Upload Trivy .json, .spdx.json, .cdx.json, or .tar vulnerability reports
  • Drag-and-drop file uploads with file type, size, and JSON structure validation
  • Real-time toast notifications for success/failure feedback
  • Sorting by Artifact Name, Timestamp, Critical, High, Medium, and Low vulnerabilities
  • Pagination with rows-per-page selection and page state stored in URL
  • Full text search by Artifact name
  • View report details:
    • Severity breakdown Pie Chart
    • Filter vulnerabilities by Severity, Package Name, CVE ID
    • Direct links to CVE databases
  • Optimized for both Development and Production environments
  • Dark Mode ready (TailwindCSS)
  • Strict backend validation (schema, file size, safe filenames)
  • Timestamps automatically adjusted to your configured timezone
  • Lightweight footprint (~100MB images)
  • Internal API metrics (/api/metrics β€” total number of reports)

πŸ›  Technologies Used

Frontend

  • React (Vite)
  • TypeScript
  • TailwindCSS
  • React Router
  • Recharts (Charts library)
  • React Hot Toast (Notifications)

Backend

  • FastAPI (Python 3.11+)
  • Uvicorn (ASGI server)
  • Pydantic + pydantic-settings
  • SQLAlchemy Core (Optional for DB backends)
  • dotenv (.env support)
  • Async/Await optimized

DevOps

  • Docker & Docker Compose
  • Clean separation of frontend/backend
  • Environment overrides for Dev/Prod
  • Health checks and metrics endpoints

UI screenshots

Trivy UI - Main Page - Reports List Trivy UI - Main Page - Report Details


πŸš€ Getting Started

1. Clone the Repository

git clone https://github.com/your-org/trivy-ui.git
cd trivy-ui

2. Set up Environment Variables

Backend .env (inside backend/.env):

# Backend environment
ENV=development
TIMEZONE=Asia/Jerusalem
UVICORN_HOST=0.0.0.0
UVICORN_PORT=8000

# Storage backend options: filesystem / sqlite / postgres
DB_BACKEND=filesystem
FILESYSTEM_STORAGE_DIR=backend/app/storage/reports
# POSTGRES_URL=postgresql+asyncpg://user:password@localhost:5432/trivyui
# SQLITE_PATH=backend/trivy_ui.db

3. Build and Run Locally

docker-compose up --build

πŸ“‚ Project Structure

.
β”œβ”€β”€ ./CONTRIBUTING.md
β”œβ”€β”€ ./LICENSE
β”œβ”€β”€ ./README.md
β”œβ”€β”€ ./backend
β”‚Β Β  β”œβ”€β”€ ./backend/Dockerfile
β”‚Β Β  β”œβ”€β”€ ./backend/README.md
β”‚Β Β  β”œβ”€β”€ ./backend/app
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/api
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── ./backend/app/api/routes.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/core
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/core/config.py
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/core/database.py
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── ./backend/app/core/exception_handlers.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/main.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/models
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── ./backend/app/models/report.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/schemas
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── ./backend/app/schemas/report.py
β”‚Β Β  β”‚Β Β  └── ./backend/app/storage
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/storage/base.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/storage/factory.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/storage/filesystem.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/storage/postgres.py
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./backend/app/storage/reports
β”‚Β Β  β”‚Β Β  └── ./backend/app/storage/sqlite.py
β”‚Β Β  β”œβ”€β”€ ./backend/logging.yaml
β”‚Β Β  β”œβ”€β”€ ./backend/logs
β”‚Β Β  β”‚Β Β  └── ./backend/logs/README.md
β”‚Β Β  β”œβ”€β”€ ./backend/requirements.txt
β”œβ”€β”€ ./docker-compose.override.yml
β”œβ”€β”€ ./docker-compose.prod.yml
β”œβ”€β”€ ./docker-compose.yml
β”œβ”€β”€ ./frontend
β”‚Β Β  β”œβ”€β”€ ./frontend/Dockerfile
β”‚Β Β  β”œβ”€β”€ ./frontend/Dockerfile.dev
β”‚Β Β  β”œβ”€β”€ ./frontend/README.md
β”‚Β Β  β”œβ”€β”€ ./frontend/dist
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/dist/assets
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/dist/assets/index-CpjW13Wg.css
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── ./frontend/dist/assets/index-Gatrr9HR.js
β”‚Β Β  β”‚Β Β  └── ./frontend/dist/index.html
β”‚Β Β  β”œβ”€β”€ ./frontend/eslint.config.js
β”‚Β Β  β”œβ”€β”€ ./frontend/index.html
β”‚Β Β  β”œβ”€β”€ ./frontend/nginx
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/nginx/default.conf
β”‚Β Β  β”‚Β Β  └── ./frontend/nginx/nginx.conf
β”‚Β Β  β”œβ”€β”€ ./frontend/postcss.config.js
β”‚Β Β  β”œβ”€β”€ ./frontend/public
β”‚Β Β  β”œβ”€β”€ ./frontend/src
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/App.css
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/App.tsx
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/api.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/components
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/components/Chart.css
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/components/LoadingSpinner.tsx
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/components/ReportDetail.tsx
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/components/ReportsList.tsx
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── ./frontend/src/components/UploadForm.tsx
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/index.css
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./frontend/src/main.tsx
β”‚Β Β  β”‚Β Β  └── ./frontend/src/vite-env.d.ts
β”‚Β Β  β”œβ”€β”€ ./frontend/tailwind.config.js
β”‚Β Β  └── ./frontend/vite.config.ts
β”œβ”€β”€ ./k8s
β”‚Β Β  β”œβ”€β”€ ./k8s/backend
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./k8s/backend/backend-deployment.yaml
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./k8s/backend/backend-pv.yaml
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ./k8s/backend/backend-pvc.yaml
β”‚Β Β  β”‚Β Β  └── ./k8s/backend/backend-service.yaml
β”‚Β Β  └── ./k8s/frontend
β”‚Β Β  β”œβ”€β”€ ./k8s/frontend/frontend-deployment.yaml
β”‚Β Β  β”œβ”€β”€ ./k8s/frontend/frontend-ingress.yaml
β”‚Β Β  └── ./k8s/frontend/frontend-service.yaml
β”œβ”€β”€ ./trivy-ui-report-details.png
└── ./trivy-ui-reports-list.png

πŸ§ͺ API Endpoints

Method Endpoint Description
GET /api/ Root alive check
GET /api/health Health check endpoint
GET /api/metrics Returns number of stored reports
POST /api/upload-report Upload Trivy file
POST /api/report Upload Trivy JSON via body
GET /api/report/{id} Fetch specific report details
GET /api/reports List reports (with filters and pagination)

βš™οΈ Configuration Options

Variable Description Example
TIMEZONE Timezone name for timestamps (pytz format) Asia/Jerusalem
DB_BACKEND filesystem, sqlite, or postgres backend filesystem
FILESYSTEM_STORAGE_DIR Path for storing uploaded reports locally backend/app/storage/reports
POSTGRES_URL PostgreSQL connection string (if using postgres) postgresql+asyncpg://...
SQLITE_PATH SQLite database path (if using sqlite) backend/trivy_ui.db

πŸ“ˆ Health & Metrics

Check health:

curl http://localhost:8000/api/health

Expected:

{"status": "ok"}

Check metrics (total reports count):

curl http://localhost:8000/api/metrics

Expected:

{"reports_count": 42}

An example how can be used in a Github Actions pipeline

# .github/workflows/trivy-scan.yml

name: Trivy Scan and Upload

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  trivy:
    name: Trivy Scan and Upload
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build Docker Image
        run: |
          docker build -t my-app:latest .

      - name: Run Trivy scan and save JSON report
        run: |
          docker run --rm \
            -v ${{ github.workspace }}:/workspace \
            aquasec/trivy:latest \
            image --format json -o /workspace/trivy-report.json my-app:latest

      - name: Upload report to Trivy UI
        run: |
          curl -X POST http://trivy-ui.default.svc/report \
            -H "Content-Type: application/json" \
            --data-binary @trivy-report.json

🧹 Best Practices Implemented

  • Strict file upload validation: max 5MB, .json or .tar only
  • Safe filenames via sanitization
  • Automatic timezone correction for reports
  • Rate limiting support (IP-based, internal)
  • Frontend error boundaries
  • Docker healthchecks ready
  • Clear CORS policies for dev vs prod
  • Strict typing across codebase (TypeScript and Python)

πŸ“‹ TODOs and Future Improvements

Item Description
Kubernetes Support Helm chart + manifests for EKS, GKE, AKS
API Authentication Bearer tokens, API keys or JWTs
Rate Limiting Enforcement per IP rate limiter to prevent abuse
RBAC Roles Admin vs Viewer accounts
HTTPS in Docker Enable TLS termination in backend
Multi-user Mode Associate reports to different users if authentication added
External Storage Support Upload directly to AWS S3, GCS, or Azure Blob
Live Updates Implement WebSocket for real-time UI refresh
Export Filtered Reports Allow users to download filtered reports as JSON
Trivy Integration (Optional) Trigger Trivy scans directly via UI (with credentials)

✍️ Author

Created with ❀️ by Itai Ganot


πŸ“œ License

MIT License β€” free to use, modify, distribute, and build on.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published