feat: chat + optmz control panel

This commit is contained in:
thanhnv
2026-07-10 16:26:30 +09:00
parent d882a9dc23
commit 7cea023dce
28 changed files with 1702 additions and 402 deletions
+203
View File
@@ -0,0 +1,203 @@
# 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/v1` when model mode is
required.
Confirm Docker first:
```bash
docker version
docker compose version
```
## 2. Start every local service
From the repository root:
```bash
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` — credentials `casan` / `casan`.
- MinIO Console: `http://127.0.0.1:19091` — credentials `casanadmin` /
`casanadmin123`.
- Control Panel: `https://localhost:18443` — accept the local self-signed
certificate. The mock OIDC flow signs in automatically as `oidc-ops` with
`org-admin` for local testing only.
Check running services at any time:
```bash
bash packages/casan-harness/scripts/bash/local-full.sh status
```
## 3. Verify infrastructure controls
```bash
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
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:
```bash
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`.
```bash
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.
```bash
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`.
```bash
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:
```bash
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:
```bash
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:
```bash
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
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:
```bash
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.