7.4 KiB
CASAN local full stack (macOS)
This guide runs the entire currently implemented CASAN stack on one Mac. It is a local production-like lab, not a production compliance claim. The Linux server is deliberately not used in this phase.
What runs locally
| Component | Address | Role |
|---|---|---|
| Vault dev / Transit | http://127.0.0.1:18200 |
KMS signing and rotation exercises |
| Mock OIDC / JWKS | http://127.0.0.1:18081 |
Approval JWT validation |
| MinIO S3 API | http://127.0.0.1:19090 |
S3-compatible object storage |
| MinIO Console | http://127.0.0.1:19091 |
S3 administration UI |
| MinIO WORM bucket | casan-worm |
Object Lock / 1-day compliance retention |
| Alert mock | http://127.0.0.1:19092 |
Alert webhook target |
| Billing mock | http://127.0.0.1:19093/usage |
Provider-usage import target |
| AgentOps dashboard | http://127.0.0.1:18080 |
Dashboard behind nginx basic auth |
| CASAN Control Panel | https://localhost:18443 |
TLS + mock OIDC + oauth2-proxy + nginx + NestJS + React |
| OmniRoute | http://127.0.0.1:20128/v1 |
Existing local OpenAI-compatible model gateway |
The Control Panel uses a different mock IdP port (18082) so it can run at the
same time as the approval IdP (18081).
1. Prerequisites
- Docker Desktop running, with at least 6 GB RAM allocated.
- Node.js 20+ and npm (needed only for host-side development and CASAN pipeline execution; the local services run in Docker).
- OmniRoute already reachable at
http://127.0.0.1:20128/v1when model mode is required.
Confirm Docker first:
docker version
docker compose version
2. Start every local service
From the repository root:
bash packages/casan-harness/scripts/bash/local-full.sh start
The first run builds the mock services and Control Panel images. Open:
- Dashboard:
http://127.0.0.1:18080— credentialscasan/casan. - MinIO Console:
http://127.0.0.1:19091— credentialscasanadmin/casanadmin123. - Control Panel:
https://localhost:18443— accept the local self-signed certificate. The mock OIDC flow signs in automatically asoidc-opswithorg-adminfor local testing only.
Check running services at any time:
bash packages/casan-harness/scripts/bash/local-full.sh status
3. Verify infrastructure controls
bash packages/casan-harness/scripts/bash/local-full.sh verify
This performs live Vault Transit sign/verify, gets an RS256 JWT from the mock OIDC IdP and validates it via JWKS, writes a retained object to MinIO, sends an alert, imports billing telemetry, and accesses the authenticated dashboard.
For the stricter TLS/OIDC Control Panel browser smoke:
bash packages/casan-harness/scripts/bash/local-full.sh smoke
smoke is intentionally isolated and stops its temporary Control Panel stack
when complete. Run start again if you want the UI to remain up afterwards.
4. Connect CASAN to OmniRoute
CASAN now supports an explicit OpenAI-compatible gateway model syntax. It does not relax the public OpenAI endpoint hardening: the custom URL is required and, by default, may only be localhost. Keep secrets out of shell history and Git.
First load your key into the current shell using the mechanism you normally use
(for example a password manager or a non-tracked .env.local). Then list model
IDs that OmniRoute exposes:
curl -fsS http://127.0.0.1:20128/v1/models | python3 -m json.tool
Configure a returned model ID. CASAN_OPENAI_COMPATIBLE_API_KEY may be a
dedicated OmniRoute key; if omitted, the router falls back to OPENAI_API_KEY.
export CASAN_OPENAI_COMPATIBLE_BASE_URL=http://127.0.0.1:20128/v1
export CASAN_OPENAI_COMPATIBLE_API_KEY="$OPENAI_API_KEY"
export CASAN_MODEL_PRIMARY='openai-compatible:auto/best-coding'
export CASAN_CHAT_MODEL_MODE=model
export CASAN_CHAT_MODEL_PROVIDER=omniroute
export CASAN_PREFLIGHT=1
For the Dockerized Control Panel, copy the provided template and replace only
the key locally. Docker uses host.docker.internal so the Linux container can
reach OmniRoute on the Mac host.
cp infra/local-prod/casan.local.env.example infra/local-prod/casan.local.env
# Edit casan.local.env in your editor and replace the placeholder key.
bash packages/casan-harness/scripts/bash/local-full.sh start
Do not set a bare localhost URL in this file: inside the Control Panel
container, localhost means the container itself, not your Mac.
Run a non-destructive router smoke. A successful response records real token
usage in .specify/logs/level5/provider-usage.jsonl.
printf 'Return exactly: CASAN_OK\n' >/tmp/casan-prompt.txt
bash packages/casan-harness/scripts/bash/model-router.sh \
/tmp/casan-prompt.txt /tmp/casan-model-result.json --role generate \
--model "$CASAN_MODEL_PRIMARY"
python3 -m json.tool /tmp/casan-model-result.json
The configured omniroute chat provider is classified as a gateway and always
forces CASAN's preflight data-governance check before prompt content is sent.
This is intentional: OmniRoute could route a request to a cloud model even when
the first selected model is local.
To use a gateway on a private-LAN host later, explicitly name it; never use an open allowlist:
export CASAN_OPENAI_COMPATIBLE_BASE_URL=http://192.168.1.5:20128/v1
export CASAN_OPENAI_COMPATIBLE_ALLOWED_HOSTS=192.168.1.5
Use HTTPS and a real certificate before moving this beyond a trusted LAN.
Local Ornith default for the Control Panel
The local Docker Control Panel now defaults to the existing host Ollama model
ornith:9b. It reaches Docker Desktop's host bridge at
host.docker.internal:11434; CASAN permits only that exact bridge when the
local compose profile explicitly enables it. If Ollama is unavailable, chat
returns its deterministic evidence answer instead of fabricating a model result.
Use OmniRoute/OpenAI only when you deliberately want the gateway route. Create
casan.local.env as described above and set:
CASAN_CHAT_MODEL_PROVIDER=omniroute
CASAN_OPENAI_COMPATIBLE_BASE_URL=http://host.docker.internal:20128/v1
CASAN_OPENAI_COMPATIBLE_API_KEY=your-key
5. Run CASAN with local models
For model-backed source generation, use the same environment and enable it only for the invocation:
CASAN_GEN_MODE=model CASAN_PREFLIGHT=1 \
node scripts/casan-step.mjs 01-srs 1
CASAN continues to fall back safely to deterministic templates if the gateway
is unavailable or the output is rejected by a harness gate. For governed chat,
start the Control Panel and select the omniroute provider through the existing
model configuration; the default remains deterministic/offline.
6. Stop and reset
Stop all containers while preserving MinIO data:
bash packages/casan-harness/scripts/bash/local-full.sh stop
To remove only the lab's persisted object-store data, first stop the lab, then:
docker volume rm casan-local-prod_minio-data
This is destructive and cannot be undone. Do not use it if the MinIO bucket has evidence you need to retain.
Current scope and next phase
This local environment includes every currently implemented CASAN component. It intentionally uses Vault dev mode, self-signed TLS, mock IdPs, local MinIO, and mock alert/billing endpoints. Production promotion to the Linux server should replace those with managed Vault/KMS or HSM, real S3 Object Lock, real OIDC, HTTPS certificates, a secret manager, backup/restore tests, and firewall rules; it is a separate deployment exercise.