Files
CASAN/packages/casan-control-panel/README.md
T

230 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CASAN Ops Console (Plan-13 Track 1/2/3/4 + Command Center) — Control Panel
Real **NestJS API + React UI** that surfaces CASAN harness telemetry and governed settings
management. This is the `casan-platform` **Control Plane** preview. “Platform”
is a product edition, not a CASAN Maturity L3 claim.
Monitoring remains read-only ("Đọc ≠ Ghi"). Settings writes go through RBAC and the
harness-owned governance CLI; the UI never writes harness files directly or bypasses a gate.
```
backend/ NestJS API (/api/v1 + /healthz) over .specify telemetry + governed settings
frontend/ React + Vite + Tailwind + TanStack Query Ops Console + Settings/Approvals/Kill-switch/FinOps/Command/Chat pages
```
## Run (local)
Preferred golden path from an adopted project:
```bash
casan dashboard start # starts API + UI, enrolls the local deep link
casan dashboard status
casan view # opens the most recent prompt trace
casan dashboard stop
```
Manual developer mode:
```bash
npm install # from repo root (picks up the workspaces)
npm run console:api # NestJS API → http://127.0.0.1:3010/api/v1
npm run console:ui # Vite UI → http://127.0.0.1:5174 (proxies to the API)
```
Open http://127.0.0.1:5174 — panels show REAL metrics from `.specify/logs/**`.
## API (`ok()`-enveloped except `/healthz`)
`GET /api/v1/overview` · `runs` (+ `runs/:traceId`) · `governance` · `security` ·
`incidents` · `tools` · `traceability` · `drift` · `cost` · `GET /healthz` (200 fresh /
503 stale — fail-loud, mirrors `dashboard-server.py`).
Harness reports:
- `GET /api/v1/reports` — versioned H1–H7 report catalog and availability.
- `GET /api/v1/reports/h6?project=<id>&from=<ISO>&to=<ISO>&run=<id>` — H6 AgentOps
report from the same runtime metrics, provider usage and alert files as the Control Panel.
- `GET /api/v1/reports/h6/export?format=html|json&...` — standalone, print-ready HTML
or machine-readable JSON export. Both formats serialize the same filtered report object;
no maturity score is hard-coded.
- `/reports/h6` — UI report view with project, time-range and run filters plus source-level
freshness and data-quality warnings.
- `GET /api/v1/reports/run/:traceId` and `/export?format=html|json` — complete
per-prompt H1–H7 assurance receipt with truthful H6 availability.
- `POST /api/v1/ingest/turn` — optional central ingestion. Disabled unless
`CASAN_CP_INGEST_TOKEN` is set; requests require a five-minute timestamp and
HMAC-SHA256 signature. Raw prompt/tool content keys are rejected.
Core always writes a sanitized pending envelope locally first. Central delivery
is asynchronous and never delays or changes a prompt verdict:
```bash
export CASAN_CONTROL_PLANE_TOKEN='use-a-secret-manager-in-production'
casan init \
--dashboard-url https://casan.example \
--ingest-url https://casan.example/api/v1/ingest/turn
```
The server receives the same secret as `CASAN_CP_INGEST_TOKEN`. The secret name,
not the secret value, is stored in project configuration.
Metrics export: `GET /api/v1/metrics` provides Prometheus text exposition for
aggregate freshness, run/failure/cost/token and H4/H5/action/incident counters.
It intentionally contains no tenant, actor, trace, prompt or Evidence Pack
labels. In production restrict the path at the authenticated reverse proxy to
the monitoring network or service account.
Command Center:
- `GET /api/v1/command` — Plan-13 §8.6 read-only executive surface. Returns eight
evidence-backed widgets with provenance envelopes
`{source, artifact_path, commit, run_at, verified, status}`, plus executive briefing
rows and a live governance ticker. The `/command` UI exposes the same data with a
VI/EN briefing toggle and evidence drawer.
Settings management:
- `GET /api/v1/settings` — list policy/current values/audit tail; viewer-readable.
- `POST /api/v1/settings` — governed setting write. Requires `x-casan-role` with write
permission; calls `rbac-check.py` before `control-plane-settings.py set`.
- `POST /api/v1/settings/rollback` — governed rollback through the same core CLI.
Goal workspace context:
- `GET /api/v1/goals/projects` — lists active project IDs and context roots from the
harness-owned project registry after RBAC filtering; browser-supplied paths are never accepted.
- `POST /api/v1/goals` requires `{ goal, projectId }`. H1 resolves the registry again,
produces a size-limited redacted manifest/snapshot, and gives the exact same snapshot to
local and cloud models. Account-model CLIs remain inside an empty temporary sandbox.
- Goals requesting workspace side effects make the producer and reviewer return a unified
patch. CASAN validates its paths and preconditions, stores it as a tenant-scoped artifact,
creates a `goal.workspace.execute` proposal, and finishes as `requires_approval` without
modifying source files.
- `POST /api/v1/goals/:id/apply` accepts only a patch whose proposal is already approved by
a different actor. The executor verifies the artifact hash, applies it, runs fixed
project build/test commands, and reverses the patch if verification fails.
Local management headers: `x-casan-actor`, `x-casan-role`, `x-casan-project`,
`x-casan-tenant`. Missing role defaults to `viewer`, so writes fail closed.
Kill-switch management:
- `GET /api/v1/kill-switch` — list active kill-switches from `kill-switch.sh status`.
- `POST /api/v1/kill-switch/engage` — RBAC-gated engage (`operator` or stronger).
- `POST /api/v1/kill-switch/clear` — RBAC-gated clear (`org-admin`; strict approval remains
enforced by the harness CLI in production mode).
Approval inbox / HITL:
- `GET /api/v1/approvals?status=pending` — list proposals and oversight tail.
- `POST /api/v1/approvals/submit` — submit a governed proposal; delegation is resolved
by harness `approval-inbox.py` + `delegation-policy.yaml`.
- `POST /api/v1/approvals/decide` — approve/reject with SoD and reason; strict mode
or supplied `approvalJwt` is verified by harness `approval-verify.sh`; approved
settings proposals apply through `control-plane-settings.py`.
Governed Chat (Plan-18 MVP-0/1/2):
- `POST /api/v1/chat/ask` — Ask CASAN endpoint. The API only wraps harness
`chat-turn.py`; router verdicts, H4 input/output scan, action-gate decisions,
Plan-17 loop-run certification, H5 chat audit, H6 token metrics, evidence source
selection, and operator action execution remain harness-owned.
- `GET /api/v1/chat/actions` — list registered operator actions from
`operator-actions.yaml`; no free-command execution is exposed.
- `GET /api/v1/chat/agents` — list governed agents from `agent-registry.yaml`
with role visibility; selected agent/skill/delegation are bound by harness
`chat-agent-resolver.py`.
- `GET /api/v1/chat/audit/verify` — verifies the chat audit hash chain.
- `GET /api/v1/chat/replay?chatId=<id>&tenant=<id>` — verifies chat-chain integrity,
evidence artifact hashes, and OPERATOR loop trace replay through harness
`chat-replay.py`; non-default tenants read only their tenant partition.
- `GET /api/v1/command` — includes the `chat_loop` Command Center widget backed
by chat audit/replay evidence, loop ticker rows, and token budget gauge.
- Delegation escalation returns `ESCALATED` and creates a pending `chat.escalate`
proposal in the approval inbox.
- CODEGEN requests are draft-only: `codegen-draft` outputs a state artifact, runs
`artifact-scan.sh` + `tool-output-scan.sh`, certifies through Plan-17 loop-run,
and never writes to the source tree.
- Non-default tenant chat state is resolved through `tenant-store.sh`; replay path
overrides are guarded, audit snapshots are encrypted with `tenant-crypt.sh`, and
tenant kill-switch/quota checks run before chat work.
- `/chat` UI shows actor/role scope, `mode/risk/decision` badges, certified answer,
evidence sources, registered operator actions, agent binding, loop certification,
codegen draft scan status, action-gate status, router details, and audit hash. Side-effect requests outside
registered actions return governed `BLOCK` or `NOT_SUPPORTED` responses; operator
side effects are held until the loop draft is certified.
- `/command` UI renders the Chat/Loop widget in the existing evidence drawer flow.
- `/approvals` UI accepts an approval JWT for strict reviewer identity checks.
FinOps/SLO:
- `/finops` UI reads `GET /api/v1/cost` plus `GET /api/v1/settings`.
- Provider cost/tokens come from provider usage telemetry.
- KPI/SLO tiles come from `14-business-kpi-report.json`.
- Budget status uses `cost.absolute_cap_usd` when configured; otherwise it shows
`not configured`.
Data sources + aggregation mirror `packages/casan-harness/tests/generate-agentops-dashboard.py`.
App root + telemetry paths resolve via the same marker walk-up as `casan-paths.sh`
(`.specify` or `packages/casan-harness`). The canonical source variables are
`CASAN_TELEMETRY_METRICS_LOG`, `CASAN_TELEMETRY_PROVIDER_LOG`, and
`CASAN_TELEMETRY_ALERTS_LOG`; legacy dashboard/control-panel names remain accepted as
compatibility aliases. Freshness is calculated independently from each file's mtime using
`CASAN_DASHBOARD_STALE_S` (default `3600`).
## Security posture (MVP)
Binds `127.0.0.1` by default. Refuses a non-loopback bind under `CASAN_PROFILE=prod` /
`CASAN_CP_STRICT=1` unless `CASAN_CP_TRUST_AUTH_PROXY=1` is set for an authenticated reverse
proxy that overwrites identity headers. Management endpoints are RBAC-gated via the harness
`rbac-check.py`; IdP group claims such as `casan-approver` are mapped to RBAC roles through
the same harness engine.
## Test
```bash
npm run console:test # backend telemetry/settings/approvals/kill-switch/auth mapping/command/chat contract
npm run console:build # backend tsc + frontend typecheck/vite build
```
## Production-Like Smoke
```bash
bash packages/casan-control-panel/scripts/local-prod-smoke.sh
```
The scaffold includes `Dockerfile.control-panel-api`, `Dockerfile.control-panel-ui`, and
`nginx/control-panel.conf`. Nginx protects UI/API through oauth2-proxy `auth_request`,
overwrites browser-supplied `X-CASAN-*` headers, and passes IdP group claims to the API for
RBAC mapping. The local smoke starts a self-signed HTTPS stack with a mock OIDC IdP and
expects `CP_LOCAL_SMOKE_PASS https_oidc=true actor=oidc-ops role=org-admin`; it also
asserts the Command Center returns all nine widgets with provenance envelopes and invokes
`managed-prod-smoke.sh` with the authenticated mock-IdP cookie jar. A passing local run
therefore emits both `CP_LOCAL_SMOKE_PASS ...` and
`CP_MANAGED_SMOKE_PASS actor=oidc-ops role=org-admin widgets=9`.
Managed production readiness is intentionally a stronger, fail-closed contract: it
requires a DNS-matching TLS certificate, enterprise OIDC, non-dev Vault Transit,
an actual S3 Object Lock COMPLIANCE write, and CI-attested digest-pinned images.
Follow [the Linux handoff guide](../../infra/production/README.md), then run:
```bash
CASAN_CP_PROD_ENV=infra/production/casan-prod.env \
bash packages/casan-control-panel/scripts/prod-readiness-check.sh
```
Managed production endpoint smoke, once DNS/TLS/OIDC are deployed:
```bash
CASAN_CP_BASE_URL=https://control-panel.example.com \
bash packages/casan-control-panel/scripts/managed-prod-smoke.sh
```
That unauthenticated smoke must report auth protection and spoofed-header blocking. To also
verify authenticated identity mapping and Command Center behind the enterprise IdP, pass an
exported browser cookie jar for a real logged-in session:
```bash
CASAN_CP_BASE_URL=https://control-panel.example.com \
CASAN_CP_COOKIE_JAR=/secure/path/control-panel-cookies.txt \
bash packages/casan-control-panel/scripts/managed-prod-smoke.sh
```
## Not in this pass
Live managed host/cert/enterprise IdP traffic cutover. See
`docs/plans/CASAN_PLAN_13_CONTROL_PLANE.md`.