{
  "_readme": [
    "Template for IDSconf.json — the OPNsense intrusion-detection config used by",
    "digest-engine/ingest/opnsense_ids.py. JSON has no comment syntax, so the",
    "documentation lives in these underscore-prefixed keys; the module ignores",
    "every key it does not know about, so you can leave them in place.",
    "",
    "INSTALL:",
    "  cp digest-engine/IDSconf.json.example /opt/smart-home/digest/data/IDSconf.json",
    "  chmod 600 /opt/smart-home/digest/data/IDSconf.json",
    "  $EDITOR /opt/smart-home/digest/data/IDSconf.json",
    "That directory is already bind-mounted into the container as /data, which is",
    "where OPNSENSE_IDS_CONF_PATH points by default. The real IDSconf.json is",
    "git-ignored (root .gitignore) exactly like digest-engine.env — only this",
    "template is ever committed. Then set ENABLE_OPNSENSE_IDS_INGEST=true in",
    "digest-engine.env; it is false by default.",
    "",
    "ON OPNSENSE, BEFORE THIS WORKS:",
    "  1. Suricata is core, not a plugin — no os-suricata install is needed. Enable",
    "     it at Services -> Intrusion Detection -> Administration: tick Enabled,",
    "     pick the interface(s) to watch, leave IPS mode off unless you want it,",
    "     then Download -> select rulesets (ET Open is free) -> Download & Update.",
    "     If Suricata is not enabled and running, this module reports ids_status",
    "     and no alerts, which is the honest answer rather than a silent zero.",
    "  2. Create an API key: System -> Access -> Users -> (pick or create a user)",
    "     -> API keys -> +. OPNsense downloads a .txt holding the key and secret;",
    "     they are shown once. Auth is HTTP basic with key as username, secret as",
    "     password. Paste them below.",
    "  3. Scope that user: give it ONLY the 'Services: Intrusion Detection'",
    "     privilege, no shell access, no other pages. READ THIS HONESTLY: OPNsense",
    "     ACLs are page-level, not read/write-level. That single privilege matches",
    "     'api/ids/*', which includes start/stop/reconfigure/drop-alert-log as well",
    "     as the alert query. There is no narrower built-in privilege. The",
    "     read-only guarantee therefore comes from opnsense_ids.py never calling",
    "     those endpoints, not from OPNsense enforcing it — so keep this key off",
    "     any account that has other privileges, and treat it as a credential that",
    "     could restart your IDS if it leaked."
  ],

  "_base_url": "Scheme + host (+ port if not 443) of the OPNsense web GUI. No trailing path.",
  "base_url": "https://opnsense.example.lan",

  "_api_key": "From System -> Access -> Users -> API keys. Sent as HTTP basic auth.",
  "api_key": "",
  "api_secret": "",

  "_verify_tls": [
    "true (default), false, or a path to a CA bundle inside the container.",
    "OPNsense ships a self-signed certificate, so a stock install will fail TLS",
    "verification. Prefer copying the firewall's CA into the digest data volume",
    "and putting its path here over setting false: the container host and the",
    "firewall are on the same flat LAN (no VLAN segmentation is implemented in",
    "this project yet — see docs/project-plan.md), so nothing else is protecting",
    "this credential in transit."
  ],
  "verify_tls": true,

  "_interfaces": [
    "Optional allow-list of raw device names to keep alerts from, e.g.",
    "[\"igb0\", \"vtnet1\"]. These are the kernel device names Suricata writes to",
    "eve.json as in_iface, NOT the friendly OPNsense names (LAN/WAN) — check",
    "Interfaces -> Assignments for the mapping. Empty means every interface",
    "Suricata is watching."
  ],
  "interfaces": [],

  "_max_alerts_scanned": [
    "Upper bound on how many alerts one run reads. The OPNsense API has no",
    "server-side time filter, so the digest window is applied client-side by",
    "paging newest-first until a row falls out of it; this caps that walk. If it",
    "is hit, the digest says so (window_truncated) instead of pretending the",
    "count is complete."
  ],
  "max_alerts_scanned": 5000,

  "_top_signatures": "How many distinct signatures to put in the digest context.",
  "top_signatures": 8,
  "_top_hosts": "How many local and remote IPs to put in the digest context.",
  "top_hosts": 5,

  "_packet_capture_reference": [
    "Optional free-text pointer, echoed verbatim into the digest, for raw packet",
    "captures kept ON OPNSENSE. This module never starts, downloads or analyses a",
    "capture — starting one is a write action on the firewall and is barred by the",
    "read-only invariant. See the intrusion-detection section of",
    "digest-engine/README.md for how to keep a rotating local capture instead.",
    "Example: \"rotating 10-minute captures on OPNsense at /var/log/captures/\""
  ],
  "packet_capture_reference": ""
}
