DibaGuard-Open / docs /CONSOLE.md
DibaAi's picture
DibaGuard open release: licence-clean network models, runtime, docs (no HTTP model)
e02228b verified
|
Raw History Blame Contribute Delete
8.98 kB
# DibaGuard console
> **Open-release copy** ([DibaAi/DibaGuard-Open](https://huggingface.co/DibaAi/DibaGuard-Open)). This document was written for the private build of DibaGuard. Numbers that involve the HTTP request model (`http_v2`) were measured with that model, which is **not** part of the open release; the open release ships the licence-clean network models described in `CLEAN_MODELS.md`. Licence statements inside this document are superseded by `DATA_LICENSES.md`, `CLEAN_MODELS.md` and the repository's `LICENSE`, `LICENSE-WEIGHTS` and `NOTICE` files. Sections of the original that were written in Persian were removed from this copy; nothing else was edited.
The operator console is one self-contained page served by the sidecar at `GET /console` (`/` and `/dashboard` redirect
to it). It loads nothing from anywhere else - no CDN, font or script - so it works on an air-gapped server. Tabs:
Overview, Incidents (with a per-source drawer: evidence, timeline, what the layer did and why, database remediation),
Review queue, Rules, Policy, Databases, Posture & enforcement, Teach. Light and dark themes follow the OS; the sun/moon
button overrides it.
## Opening it
The sidecar binds to `127.0.0.1` by default. From your laptop, tunnel to it:
```
ssh -N -L 8787:127.0.0.1:8787 user@guard-host
# then open http://127.0.0.1:8787/console
```
Start the sidecar with the shield layer (without `--policy` the console is read-only, engine only):
```
python -m dibaguard.llm http --models models --policy policy.json --inputs http,flows --port 8787
```
Reading needs nothing. Every write (verdicts, rules, policy, block / lift, teaching) needs the **console token**:
- set `DIBAGUARD_CONSOLE_TOKEN` in the sidecar's environment, or
- leave it unset: the sidecar generates one and prints it **once** on stderr at startup.
Click **Read-only** in the header and paste the token. It is kept in that browser tab only (sessionStorage) and
forgotten when the tab closes or you click **Unlocked** to lock again.
## Connecting an LLM (Teach)
The model is configured in the sidecar's environment, never in the page; the key never reaches the browser.
| variable | value |
|---|---|
| `DIBAGUARD_LLM_PROVIDER` | `openai` - any OpenAI-compatible `/chat/completions` endpoint (vLLM, llama.cpp server, Ollama, LM Studio, OpenAI) - or `anthropic` (Messages API) |
| `DIBAGUARD_LLM_BASE_URL` | e.g. `http://10.0.0.30:8000/v1`; for `anthropic` defaults to `https://api.anthropic.com` |
| `DIBAGUARD_LLM_MODEL` | the model name |
| `DIBAGUARD_LLM_API_KEY` | the key (optional for local servers; required for `anthropic`) |
| `DIBAGUARD_LLM_TIMEOUT` | seconds per call, default 120 |
On an air-gapped site, point `DIBAGUARD_LLM_BASE_URL` at a model served on the local network; the model must support
tool / function calling. Without an LLM, the Teach tab explains this and still offers the built-in Persian / English
rule parser.
The Rules tab can also use the connected LLM to interpret a rule written in any language (interpreter
"Connected LLM", or "Auto" when the built-in parser finds no condition). The result is shown as a precise rule first.
## The approval model
The sidecar runs the tool loop itself (`POST /console/chat`), with the dispatcher's tools (`guard_*`) plus four
console tools (`console_entity`, `console_rule_install`, `console_rule_remove`, `console_enforce`).
- **Reads run at once**: status, report, entity details, review queue, fast state, rules / policy (viewing), database
status, playbook.
- **Everything that changes state becomes a proposal**: rule install / removal, verdicts, policy changes, block / lift,
calibration, and feeding traffic to the engine (scoring can lead to actions). The model is told "proposed - not
executed" and the proposal appears in the transcript and in *Pending proposals* with its exact tool call.
- **Only you execute it**, by clicking **Approve** (`POST /console/approve`). A rule proposal installs exactly the rule
you saw in the preview - it is not re-interpreted. A mode switch additionally needs the target mode typed back.
Proposals expire after an hour; each can be decided once.
- The assistant hears your decisions (approved, rejected, failed, and your own changes from other tabs) at the start of
its next turn. The server keeps a bounded history (40 messages for the model, 300 transcript lines); **Clear** forgets it.
Policy changes from the Policy tab are validated by `Policy.validate` before they apply. Switching between REPORT and
ENFORCE asks you to type `ENFORCE` / `REPORT`, server-side (an API caller cannot skip it either). Fields that only take
effect at start-up (`alpha`, database thresholds read at load) are not editable live: edit `policy.json` and restart.
Rules and policy changed in the console live in memory; **Policy -> Effective policy -> Download** gives a
`policy.json` with the installed rules to keep them across restarts.
## Security notes
- **Bind to loopback** and reach it over SSH. If you bind elsewhere the sidecar warns at startup; put TLS and access
control in front.
- **Writes**: every `POST /console/*` needs `X-DibaGuard-Token` (or `Authorization: Bearer`), the custom header
`X-DibaGuard-Console: 1`, and `Content-Type: application/json`. Cross-site requests (`Origin` not matching `Host`,
`Sec-Fetch-Site: cross-site|same-site`) are refused. No CORS headers are ever sent, so another site's page can neither
send those headers nor read answers.
- **DNS rebinding**: `/console*` is only served when `Host` is an IP literal or `localhost`; add names (a reverse proxy)
with `DIBAGUARD_CONSOLE_HOSTS=guard.example.internal`.
- **The page** carries a CSP that pins its one inline script by hash, forbids every external load, framing, forms and
base changes. Everything shown is inserted as text - evidence, queries and user-agents from attackers never become markup.
- **The tool API** (`POST /tools/<name>`): calls that change what the layer enforces - `guard_policy` with `set`,
`guard_feedback`, `guard_rules` with `add` (not `interpret_only`), `guard_posture` when port closing is on - need the
same token **and** `X-DibaGuard-Console: 1`, and so do `guard_calibrate` / `guard_db_calibrate` (re-calibration
rewrites what the site's normal is). Reads stay open on loopback. **Traffic feeds that carry sources**
(`guard_score_http` with `client` / `t` / `status`, `guard_score_flows`, `guard_db`, `guard_rpc`) need the **feed
token** - `DIBAGUARD_FEED_TOKEN`, sent as `X-DibaGuard-Feed-Token` by the Go proxy and the authz service, which read
the same variable - or the console token: otherwise anyone who can reach the port could feed traffic that makes the
layer block an address of their choice (validation finding V-16). Without `DIBAGUARD_FEED_TOKEN` the sidecar makes
one and prints it once on stderr. A score-only `guard_score_http` (texts, no client or time) changes nothing and stays
open. `DIBAGUARD_FEEDS_OPEN=1` reopens every feed (an isolated loopback deployment only; the sidecar warns at
startup); `DIBAGUARD_FEEDS_NEED_TOKEN=1` demands the console token and header for feeds too. MCP over stdio is
unchanged (it is the local process's own channel).
- **Prompt injection**: tool results contain attacker-written text. The system prompt tells the model it is data, and
the approval gate means a manipulated model can at most *propose*; read each proposal's exact tool call before approving.
- The LLM key stays in the sidecar process; provider errors are redacted before they are shown.
## Endpoints
| method | path | |
|---|---|---|
| GET | `/console` | the page |
| GET | `/console/state` | counters, pressure, drift, mode, backend, latest alarms / actions, per-minute series |
| GET | `/console/incidents?limit=` | sources with risk, score, families, playbook names, enforcement |
| GET | `/console/entity?ip=` | one source: evidence, timeline, audit (what was done, why), explanation, remediation, verdicts |
| GET | `/console/review` | review queue (incl. `site:drift`), verdict stats, recent verdicts |
| GET | `/console/rules`, `/console/policy`, `/console/databases`, `/console/posture`, `/console/chat` | tab data |
| POST | `/console/auth` | check the token |
| POST | `/console/rules/interpret` `{text, engine: auto\|builtin\|llm}` | preview only |
| POST | `/console/rules/install` `{rule, text}` / `/console/rules/remove` `{id}` | |
| POST | `/console/policy` `{set, confirm?}` | 409 + `confirm_word` when the mode changes |
| POST | `/console/feedback` `{entity, verdict, note}` | confirm / reject / benign_source |
| POST | `/console/enforce` `{ip, action: block\|rate_limit\|challenge\|lift, reason}` | |
| POST | `/console/posture/run` | runs the audit (closes ports only if the policy allows) |
| POST | `/console/chat` `{message}` / `/console/chat/reset` | the assistant |
| POST | `/console/approve` `{id, decision: approve\|reject, confirm?, note?}` | execute or drop a proposal |