Get Started
Up and running in under five minutes with Docker Compose.
Prerequisites
Make sure you have the following installed before proceeding.
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.
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 .
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 .
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 .
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.
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 .
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>
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 â .
SPRING_DATASOURCE_URL to a PostgreSQL instance for persistent storage â see the
Configuration Reference below.