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). 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