-
Notifications
You must be signed in to change notification settings - Fork 2
Technical Installation
Cairn runs as a Docker stack: the Django application (ASGI/Uvicorn), PostgreSQL 16 and Redis 7 (real-time features). For local development and debugging, it can also run in pure Python with no Docker (see Option 3).
# 1. Copy the environment file
cp .env.example .env
# 2. Start the services
docker compose up --build
# 3. Apply migrations (in another terminal)
docker compose exec web python manage.py migrate
# 4. Create a superuser
docker compose exec web python manage.py createsuperuserThe application is available at http://localhost:8000. The admin interface is at http://localhost:8000/admin/.
Run Cairn directly from the published Docker Hub image (frousselet/cairn) without cloning the repository.
Create a docker-compose.yml file:
services:
web:
image: frousselet/cairn:latest
ports:
- "8000:8000"
environment:
SECRET_KEY: change-me-to-a-random-secret-key
DEBUG: "False"
ALLOWED_HOSTS: localhost,127.0.0.1
POSTGRES_DB: open_grc
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_HOST: db
POSTGRES_PORT: "5432"
REDIS_HOST: redis
REDIS_PORT: "6379"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
redis:
image: redis:7-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
db:
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: open_grc
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
volumes:
postgres_data:Then start the stack:
docker compose up -d
docker compose exec web python manage.py migrate
docker compose exec web python manage.py createsuperuserFor local development and step-by-step debugging, you can run the whole stack in pure Python, with no Docker and no external service. The dev settings module core.settings_local replaces PostgreSQL with a file-based SQLite database (db.sqlite3) and Redis with an in-memory channel layer, so nothing needs to be installed or started on the side.
Python is managed by mise, pinned in mise.toml (python = "latest").
- mise
-
gettext - provides the
msgfmtbinary used to compile the translation catalogs so the UI renders in French (apt install gettexton Debian/Ubuntu). Without itcompilemessagesfails withCommandError: Can't find msgfmtand the UI falls back to English.- On macOS, Homebrew's gettext is keg-only:
brew install gettextdoes not putmsgfmton thePATH. Add it explicitly, otherwisecompilemessageswon't find it:echo 'export PATH="/opt/homebrew/opt/gettext/bin:$PATH"' >> ~/.zshrc # Apple Silicon # Intel Macs: /usr/local/opt/gettext/bin - or: brew link gettext --force
- On macOS, Homebrew's gettext is keg-only:
# 1. Install the Python version declared in mise.toml
mise install
# 2. Create and activate a virtual environment, then install dependencies
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtPoint the VS Code Python extension at the mise-managed interpreter (Python: Select Interpreter → ${env:HOME}/.local/share/mise/installs/python/latest/bin/python); debugpy and the tasks then use it via ${command:python.interpreterPath}.
All commands use DJANGO_SETTINGS_MODULE=core.settings_local:
export DJANGO_SETTINGS_MODULE=core.settings_local
# Compile the translation catalogs (.po -> .mo) so the UI renders in French
# (requires gettext / msgfmt - see prerequisites)
python manage.py compilemessages
# Create the SQLite schema (applies all migrations, including the data
# migrations that seed permissions, system groups and risk criteria)
python manage.py migrate
# Either create a superuser...
python manage.py createsuperuser
# ...or load the demo dataset (see below), then start the dev server
python manage.py runserver 0.0.0.0:8000The application is available at http://localhost:8000. The defaults are dev-friendly (DEBUG=True, SECRET_KEY and ALLOWED_HOSTS fall back to safe local values), so no .env is required.
The repository ships ready-to-use VS Code configurations:
-
.vscode/launch.json: two launch configurations, Cairn: runserver (Django) and Cairn: uvicorn ASGI (Channels). PressF5to start the server under the debugger with breakpoints. Both setDJANGO_SETTINGS_MODULE=core.settings_localfor you. -
.vscode/tasks.json: support tasks (Terminal > Run Task...):-
stack: bootstrap : compiles the translation catalogs (non-fatal if
gettextis missing), runsmigrate, then seeds the demo dataset (guarded - only on an uninitialized database). It is wired as thepreLaunchTask, so a plainF5prepares the database and the French UI automatically. - stack: seed-demo : reloads the Voltara Energy demo dataset on demand.
-
stack: compile messages : recompiles the
.po->.motranslation catalogs on demand (after editing alocale/*.pofile). - stack: createsuperuser : creates an additional superuser interactively.
-
stack: bootstrap : compiles the translation catalogs (non-fatal if
To start from a clean dataset, delete db.sqlite3 and run the bootstrap task again.
To explore Cairn with realistic sample content, load the fictional Voltara Energy dataset (a mid-size renewable energy operator: ISO 27001 / NIS2 / GDPR frameworks, audits, risks, EBIOS RM study, indicators, management reviews) on a fresh, empty database:
docker compose exec -T web python manage.py shell -c "exec(open('scripts/seed_demo_data.py').read())"Then sign in with elise.moreau@voltara.example / VoltaraDemo!2026 (superuser). All seeded accounts share the same password. This script is intended for development and demo environments only.
"Ask Cairn" answers simple natural-language questions from the command palette (Ctrl+K), e.g. "Quelles décisions ont été prises lors de la dernière revue de direction ?". Every data access enforces the asking user's permissions, and the answer cites the real matching records. The LLM backend is a pluggable provider (AI_ASSISTANT_PROVIDER); the feature is off by default and the palette works unchanged when it is disabled or the backend is unreachable.
Default (Mistral AI, third-party EU-hosted API): no sidecar, no model download, no GPU.
# In .env, then restart web:
AI_ASSISTANT_ENABLED=True
AI_ASSISTANT_PROVIDER=mistral
AI_ASSISTANT_API_KEY=your-mistral-api-key
AI_ASSISTANT_MODEL=mistral-small-latestOther backends are configured the same way: openai for OpenAI (ChatGPT) or any OpenAI-compatible endpoint (vLLM, LiteLLM, LocalAI...), anthropic for Claude, and ollama for a self-hosted, no-egress deployment pointed at your own Ollama instance. With a third-party provider, the question text and the compact record fields used for routing leave the platform. Provider setup, model guidance, the data-egress detail and semantic search are all documented in docs/specs/assistant/.
Two management commands keep the risk register in sync with time and are intended to be run once a day by a cron job (host or container side):
# Set RiskAcceptance.status = EXPIRED for any active acceptance past its
# valid_until date; print upcoming expirations within --reminder-days
# (default 30) for operators to act on.
docker compose exec web python manage.py expire_risk_acceptances
# Set RiskTreatmentPlan.status = OVERDUE for any in-flight plan whose
# target_date has passed (skips COMPLETED, CANCELLED and already-OVERDUE).
docker compose exec web python manage.py mark_overdue_treatment_plansBoth accept --dry-run to preview changes. A typical host cron entry:
# /etc/cron.d/cairn-lifecycle
15 2 * * * cd /opt/cairn && docker compose exec -T web python manage.py expire_risk_acceptances
20 2 * * * cd /opt/cairn && docker compose exec -T web python manage.py mark_overdue_treatment_plansIf the semantic search of the Ask Cairn assistant is enabled (AI_ASSISTANT_SEMANTIC_ENABLED), schedule the index refresh the same way. The command is idempotent (it only re-embeds changed requirements and prunes deleted ones), so a daily run is cheap. The index is also refreshed automatically when the app starts, a deleted requirement is pruned immediately, and an administrator can force a refresh from the Administration -> Semantic index page; the daily cron is the reliable, self-healing backstop.
25 2 * * * cd /opt/cairn && docker compose exec -T web python manage.py rebuild_semantic_indexBuilt from docs/ at v0.36.0. Edits made here are overwritten by the next release : open a pull request against the source instead.
- Administration
- Ask Cairn
- Assets and suppliers
- Compliance
- The dashboard
- Finding your way
- Getting started
- Incidents
- How records move
- Organisational context
- Reports and management review
- Risks
- Trust Center
- Architecture
- Configuration
- Contributing
- The documentation system
- Installation
- Internationalisation
- Operations
- Release process
- Security
- Testing
- Adding an assistant provider
- Adding a dashboard widget
- Adding a domain entity
- Declaring a lifecycle
- Adding an MCP tool
- Adding a REST endpoint
- Adding a report
- Interface conventions
- Dashboard widgets
- Lifecycles
- MCP tools
- MCP tool parameters : Assets
- MCP tool parameters : Compliance
- MCP tool parameters : Governance and context
- MCP tool parameters : General
- MCP tool parameters : Incidents
- MCP tool parameters : Reports and management review
- MCP tool parameters : Risks
- MCP tool parameters : System and administration
- MCP tool parameters : Trust Center
- Management commands
- Models
- Permissions
- REST endpoints
- Environment variables
- MCP server
- REST API
- Assistant module (Ask Cairn)
- Module 0: User Management and Access Control
- Module 1: Context and Organization
- Module 2: Asset Management
- Module 3: Compliance
- Module 4: Risk Management
- Module 4 bis - EBIOS Risk Manager
- Module 5 : Trust Center
- Module 6 : Security Incident Management
- Management review : ISO 27001:2022 compliance (clause 9.3)