Get Started

Up and running in under five minutes with Docker Compose.

Prerequisites

Make sure you have the following installed before proceeding.

☕ Java 21 Eclipse Temurin recommended
đŸŸĸ Node.js 20 With npm included
đŸŗ Docker Docker Desktop or Engine + Compose
đŸ“Ļ Git To clone the repository

Quick Start (Docker Compose)

The fastest way to run OpenFactstore is with Docker Compose, which starts all services with a single command.

# 1. Clone the repository
git clone https://github.com/MaximumTrainer/OpenFactstore.git
cd OpenFactstore

# 2. Start all services
docker-compose up -d

# 3. Check services are running
docker-compose ps

Once running, the following services are available:

Service URL Description
Backend API http://localhost:8080 Spring Boot REST API
Frontend UI http://localhost:5173 Vue 3 web application
Swagger UI http://localhost:8080/swagger-ui.html Interactive API documentation
Grafana http://localhost:3000 Compliance dashboards (admin/admin)
Prometheus http://localhost:9090 Metrics collection

Manual Setup (Development)

To run the backend and frontend separately for development:

Backend

cd backend
./gradlew bootRun       # Starts on http://localhost:8080

Frontend

cd frontend
npm ci
npm run dev             # Starts on http://localhost:5173

Your First Compliance Trail

Walk through a complete compliance lifecycle using the REST API.

1

Create a Flow

A Flow is a template that defines the required compliance checks for a type of release.

curl -s -X POST http://localhost:8080/api/v1/flows \
  -H "Content-Type: application/json" \
  -d '{
    "name": "standard-release",
    "description": "Standard production release checks",
    "requiredAttestations": ["security-scan", "code-review", "qa-signoff"]
  }' | jq .
2

Start a Trail

A Trail is a per-release evidence collection linked to a specific artifact (e.g., a container image).

curl -s -X POST http://localhost:8080/api/v1/trails \
  -H "Content-Type: application/json" \
  -d '{
    "flowId": "<flow-id-from-step-1>",
    "artifactName": "my-service",
    "artifactVersion": "1.4.2",
    "artifactDigest": "sha256:abc123..."
  }' | jq .
3

Record an Attestation

Attestations are individual evidence records. Record your security scan result:

curl -s -X POST http://localhost:8080/api/v1/trails/<trail-id>/attestations \
  -H "Content-Type: application/json" \
  -d '{
    "type": "security-scan",
    "passed": true,
    "details": "Trivy scan: 0 critical, 2 medium (accepted)",
    "attestedBy": "pipeline-bot"
  }' | jq .
4

Check Compliance

Evaluate whether the trail satisfies all flow requirements and is cleared for deployment:

curl -s http://localhost:8080/api/v1/trails/<trail-id>/compliance | jq .

When all required attestations are recorded and policies pass, the response will show "compliant": true and the artifact is cleared for deployment.

5

Evaluate the Deployment Gate

Use the deployment gate to get a binary deploy/block decision:

curl -s -X POST http://localhost:8080/api/v1/gate/evaluate \
  -H "Content-Type: application/json" \
  -d '{
    "trailId": "<trail-id>",
    "targetEnvironment": "production"
  }' | jq .
â„šī¸
For the complete API reference including all request/response schemas, see the API Docs page or visit http://localhost:8080/swagger-ui.html when the server is running.

Dry-run Mode

Any write operation can be tested without persisting data by adding the X-Dry-Run: true header. The API will validate the request and simulate the result without making any changes:

curl -s -X POST http://localhost:8080/api/v1/trails \
  -H "Content-Type: application/json" \
  -H "X-Dry-Run: true" \
  -d '{ ... }' | jq .

Configuration Reference

All runtime settings are configured via environment variables. Here are the key options for a production deployment.

Environment Variables

Variable Default Description
SPRING_DATASOURCE_URL H2 in-memory JDBC URL for PostgreSQL, e.g. jdbc:postgresql://db:5432/factstore
SPRING_DATASOURCE_USERNAME factstore Database username
SPRING_DATASOURCE_PASSWORD none Database password
SECURITY_ENFORCE_AUTH false Set to true to require API key or JWT on all endpoints
FACTSTORE_SCM_ENCRYPTION_KEY dev key 32-character AES key for encrypting SCM tokens at rest
FACTSTORE_EVENTS_PUBLISHER logging Event bus: logging | rabbitmq | inmemory | none
FACTSTORE_CQRS_ROLE none CQRS deployment: command (write) or query (read-only)
SPRING_RABBITMQ_HOST localhost RabbitMQ hostname (only used when FACTSTORE_EVENTS_PUBLISHER=rabbitmq)
OPA_MODE embedded OPA policy mode: embedded (built-in evaluator) or external
OPA_URL none URL of external OPA server when OPA_MODE=external
SERVER_PORT 8080 HTTP port the backend listens on

Production Docker Compose example

A minimal production-ready compose file with PostgreSQL, RabbitMQ, and authentication enabled:

# docker-compose.prod.yml
services:
  factstore:
    image: ghcr.io/maximumtrainer/openfactstore:latest
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL:     jdbc:postgresql://postgres:5432/factstore
      SPRING_DATASOURCE_USERNAME: factstore
      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
      SECURITY_ENFORCE_AUTH:      "true"
      FACTSTORE_SCM_ENCRYPTION_KEY: ${SCM_KEY}
      FACTSTORE_EVENTS_PUBLISHER: rabbitmq
      SPRING_RABBITMQ_HOST:       rabbitmq
    depends_on:
      postgres:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 15s
      timeout: 5s
      retries: 5

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB:       factstore
      POSTGRES_USER:     factstore
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "factstore"]
      interval: 10s
      retries: 5

  rabbitmq:
    image: rabbitmq:3-management-alpine
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "ping"]
      interval: 10s
      retries: 5

volumes:
  pgdata:

CLI configuration

The factstore CLI stores its configuration in ~/.factstore.yaml. Run factstore configure to set it interactively, or create the file manually:

# ~/.factstore.yaml
host:        https://factstore.example.com
token:       fs_pat_your_api_key_here
query_host:  https://factstore-query.example.com  # CQRS read replica (optional)

All CLI settings can also be provided as environment variables:

FACTSTORE_HOST=https://factstore.example.com \
FACTSTORE_TOKEN=fs_pat_... \
factstore attest --type unit-tests --trail <trail-id>
✅
Use SECURITY_ENFORCE_AUTH=true and rotate API keys regularly in production. Each CI pipeline should use a dedicated SERVICE_ACCOUNT API key with least-privilege scoping.

Further Reading

For the complete user guide including CI/CD integration examples, environment configuration, OPA policy authoring, and production hardening, see the USER_GUIDE.md on GitHub ↗ .

âš ī¸
The default configuration uses an in-memory H2 database. All data is lost on restart. Set SPRING_DATASOURCE_URL to a PostgreSQL instance for persistent storage — see the Configuration Reference below.