Skip to content

v2.0.0

Choose a tag to compare

@rknightion rknightion released this 04 Jul 04:55
162e60c

2.0.0 (2026-07-04)

⚠ BREAKING CHANGES

  • smart: the SMART collector is now off by default. Set --exporter.enable-smart (env OPNSENSE_EXPORTER_ENABLE_SMART=true) to restore the opnsense_smart_* metrics.
  • arp,ndp: opnsense_arp_table_entries and opnsense_ndp_entries per-entry series are no longer emitted by default. Set --exporter.enable-arp-details / --exporter.enable-ndp-details to restore them; otherwise use the new opnsense_arp_table_entries_total / opnsense_ndp_entries_total aggregates.
  • interfaces: distinguish unknown link state from down so PPPoE WANs aren't reported down
  • when --exporter.instance-label is unset, the instance label now defaults to the configured OPNsense address rather than the API hostname. Set --exporter.instance-use-hostname to keep hostname-derived labels, or set --exporter.instance-label explicitly.
  • firewall: opnsense_firewall_interface_hits_total is renamed to opnsense_firewall_interface_log_entries_recent and changed from counter to gauge. Any user dashboards/alerts using rate()/increase() on the old name must switch to plotting the new gauge directly. The shipped dashboard is updated.
  • grafana: grafana/alerts/opnsense.rules.yaml is removed. Users loading that file into Prometheus/Mimir/the Grafana Cloud ruler should migrate to the Grafana-managed manifests under grafana/alerts/grafana-managed/ (gcx resources push).

Features

  • apicapture: resolve OPS_API_KEY_FILE/OPS_API_SECRET_FILE like the exporter (428353b), closes #157
  • arp,ndp: gate per-entry metrics behind opt-in details flags (2ac1221), closes #125
  • collector: add disable switches for interfaces, protocol, services (ef94751), closes #143
  • config: make OPNsense API timeout and retry count configurable (045571f), closes #140
  • docs: align docs site with m7kni.io brand + server-side SEO/LLM metadata (9bca073), closes #70
  • grafana: drop portable Prometheus rules format, ship Grafana-managed alerting only (2af458a), closes #76 #95
  • metrics: add per-endpoint API request count and duration self-metrics (802c53a), closes #126
  • security: warn at startup when --opnsense.insecure disables TLS verification (2d3914d), closes #159
  • smart: make SMART collector opt-in (--exporter.enable-smart, default-off) (4c8af5c), closes #139

Bug Fixes

  • activity: parse thread states independently so zombie/stopped states don't zero metrics (73ba3f8), closes #82
  • alerts: make OPNsenseEndpointErrors for:15m require sustained errors (586563a), closes #94
  • apicontract: filter abstract-controller phantom endpoints from the manifest (9ab2ee9), closes #146
  • apicontract: isolate per-controller parse failures in extract.py (fca0054), closes #111
  • captiveportal: decode zones map serialized as a JSON array (27fef5b), closes #73
  • carp: source VIP label from the subnet field and dedupe multi-address vhids (30641c1), closes #166
  • certificates: omit valid_from/valid_to for pending CSRs instead of epoch 0 (b80a1da), closes #167
  • chrony: skip sources metrics on sub-fetch failure instead of false zero (4aed2cf), closes #163
  • ci: match drift issue by label+title, not the broken bot-login filter (5944a81), closes #83
  • ci: surface api-contract verb-drift warnings instead of burying them (e8cfff8), closes #93
  • collector: bound no-deadline collections to stop a stalled box blackout (4baabb8), closes #128
  • collector: dedupe services/wireguard/ntp label tuples to prevent scrape-wide 500s (45e3403), closes #85
  • collector: distinguish deadline-expired skipped scrapes from completed ones (6664350), closes #122
  • collector: emit cumulative counters as CounterValue in firewall/ipsec/protocol (5621823), closes #106
  • collector: keep dhcpv4/acme/smart/dyndns silent when their plugin is absent (52a72d8), closes #87
  • collector: skip scalar metrics whose backing sub-call failed in pf-stats/system (47145c2), closes #91
  • collector: surface interfaces-overview fetch failures via success/errors (14d9190), closes #123
  • collector: use panic: sentinel on endpoint-errors label, not subsystem slug (86326fc), closes #120
  • config: consistent env-var surface — telemetry-path envar + prefixed *_FILE aliases (6a4d64e), closes #141
  • config: empty OPS_API_KEY_FILE/OPS_API_SECRET_FILE falls back to flag (9e56123), closes #109
  • config: reject empty/invalid --web.telemetry-path instead of panicking (945cfb4), closes #108
  • config: validate Pyroscope server-address scheme at startup (e328a7c), closes #142
  • crowdsec: mark bouncers/machines absent on row decode failure instead of false zero (75c758f), closes #104
  • dashboard: add $device variable so pf-traffic/netflow panels stop blanking (b8506a5), closes #98
  • dashboard: gate DHCP backend rows on presence, not lease count (2d16b13), closes #114
  • dashboard: key multi-query table renames/units on Value #A..N, not metric names (4800d96), closes #97
  • dashboard: match Exporter Runtime panels on job=~"opnsense.*", not hardcoded job (479560e), closes #113
  • dashboard: scale epoch-seconds timestamps to ms for dateTimeAsIso panels (baacea2), closes #78
  • dashboard: show lease-expiry column in dnsmasq/Kea lease-detail tables (0dbfe5c), closes #112
  • deps: update module github.com/grafana/pyroscope-go to v1.4.0 (#69) (fb582e6)
  • deps: update module github.com/prometheus/exporter-toolkit to v0.17.0 (#62) (0783001)
  • deps: update module github.com/prometheus/exporter-toolkit to v0.17.1 (#65) (77f9eb2)
  • deps: update module google.golang.org/grpc to v1.82.0 (#63) (637e901)
  • docgen: cover top-level Collector metrics + fatal on unparsed constructors (02a90a2), closes #119
  • docgen: derive metric Type from emission ValueType, not _total suffix (3dc7c1c), closes #100
  • docgen: make doclint flag/env extraction shape-based and lint grafana tabs (f6fbbde), closes #151
  • docker: rename build ARG Version→VERSION so published images embed the version (c92830e), closes #79
  • docs: correct container UID to 65532 (distroless nonroot), not 65534 (44fa537), closes #115
  • docs: pin grafana/README tab list + alert/recording counts to generated data (53061bb), closes #116
  • docs: pin sub-collector count (47) in CLAUDE.md + 3 docs pages, close drift gap (1774373), closes #117
  • docs: replace oversized gradient hero with a compact docs-friendly intro (fca3dc6), closes #70
  • firewall: filter pfctl pseudo-entries and strip mutable (skip) suffix from interface label (9009e04), closes #105
  • firewall: re-type interface hit count as a sliding-window gauge, not a counter (8b3fdfa), closes #74
  • frr: make frrAFLabel lossless per SAFI to avoid duplicate BGP series (3fda9d2), closes #162
  • gateways: emit status for enabled monitor-disabled gateways (GatewayDown blind spot) (85a95ec), closes #77
  • haproxy: omit HTTP response-code counters for tcp-mode proxies (4b6cc40), closes #164
  • interfaces: distinguish unknown link state from down so PPPoE WANs aren't reported down (cfd1d63), closes #86
  • interfaces: parse counter fields tolerantly so one bad field doesn't drop all interface metrics (b0f9ee0), closes #102
  • k8s: pin image tag and add seccomp/SA-token hardening to example manifest (7f5df45), closes #147
  • k8s: raise example scrapeTimeout to 30s and use resolvable Service DNS (393f998), closes #99
  • main: gracefully drain HTTP server on SIGTERM/SIGINT instead of os.Exit(0) (123b774), closes #161
  • make: pass API creds to local-run/capture via env, not world-readable argv (8729693), closes #160
  • ntp: parse unit-suffixed ntpq when/poll intervals instead of coercing to 0 (f9001f0), closes #89
  • openvpn: count only real client rows as sessions (a0b9c70), closes #88
  • opnsense: widen byte/packet counter fields to int64 for 32-bit source builds (4ef3662), closes #103
  • otlp: close three config-validation gaps that silently break export (dcd76f3), closes #92
  • otlp: isolate gatherers so one bad collector can't black out export (ab0fdcc), closes #101
  • otlp: post to the /v1/metrics signal path for base-URL endpoints (22d841e), closes #80
  • profiling: flush final Pyroscope window on shutdown instead of dropping it (962bead), closes #121
  • protocol: expose IPv6/ICMPv6 stats instead of silently dropping them (579a2b2), closes #165
  • resilience: short-circuit when firewall unreachable + backoff/jitter retries (d228260), closes #127
  • resolve instance label deterministically instead of via a startup race (3ec7122), closes #75
  • server,collectors: stop duplicate label tuples from 500-ing the whole scrape (6980c93), closes #81
  • server: reject NaN/Inf/absurd scrape-timeout header values (c8e574b), closes #124
  • system: correct DST-transition skew in uptime and config_last_change (f49edc2), closes #107
  • unbound: capture all RR query types, not a fixed 16-field whitelist (6b955fd), closes #138
  • unbound: skip stats series when unbound-control is unavailable (c6b652e), closes #90
  • unbound: stop clamp_min(denom,1) collapsing cache hit ratio below 1 qps (0381b26), closes #96

Performance

  • mbuf: read extended fields from systemMbuf, skip redundant API call (3712561), closes #137
  • opnsense: parallelize independent multi-endpoint Fetch functions (baa4964), closes #129

Miscellaneous

  • deps: update anthropics/claude-code-action action to v1.0.160 (#61) (4966911)
  • deps: update anthropics/claude-code-action action to v1.0.161 (#64) (511cee1)
  • deps: update anthropics/claude-code-action action to v1.0.162 (#66) (a442589)
  • deps: update anthropics/claude-code-action action to v1.0.163 (#71) (5196a33)
  • deps: update docker/build-push-action action to v7.3.0 (#67) (54eba0e)
  • deps: update docker/setup-buildx-action action to v4.2.0 (#68) (4b6eb3e)
  • deps: update module github.com/anchore/syft to v1.46.0 (#169) (0960135)
  • deps: update module github.com/anchore/syft/cmd/syft to v1.46.0 (#170) (7a86913)
  • deps: update module github.com/google/go-licenses to v2 (#171) (c10f69e)
  • docs: remove committed zensical site/ build output and gitignore it (224998e), closes #152
  • remove Snyk from CI (0c80fcf)

Documentation

  • apicontract: correct false "live-box stage (P3)" exemption claim (7b777a1), closes #110
  • drop false promhttp_* claim from --web.disable-exporter-metrics help (360e12d), closes #149
  • firmware: correct misleading needs_reboot help text (1d66d54), closes #168
  • geo: content-shape pass for LLM/search retrievability (eb025ae)
  • mark shipped collectors COMPLETED in stale todos.txt (7fe6e8b), closes #158
  • troubleshooting: flag the activity collector as the top scrape-latency cost (6be042e), closes #150

Build & Infrastructure

  • docker: digest-pin the golang builder image + Renovate pinDigests (b6069f8), closes #148

Tests

  • contract: derive postEndpoints from POST call sites to catch drift (2e54b96), closes #145
  • contract: extend response-shape contracts beyond healthCheck (dabe778), closes #144
  • main: gate that every collector disable switch is wired in main.go (4f99761), closes #153
  • opnsense: drop duplicated testEndpoints(), build test clients from defaultEndpoints() (386aa39), closes #154
  • opnsense: pin hasync single-node {"response": false} shape (ed8dec9), closes #156
  • opnsense: use raw JSON fixtures for services/arp/ntp/carp instead of mustMarshal(struct) (10b1831), closes #155

CI/CD

  • add OpenSSF Scorecard via shared reusable workflow (3759427)
  • bump shared rknightion reusables v1.0.0 -> v1.3.1 (f8c2fa0)
  • drop CodeQL pull_request trigger to trim Actions fan-out (3bb206c)
  • grafana: enforce dashboard coverage, regen freshness & manifest validity (311267e), closes #84
  • lint: pin golangci-lint version and enforce gofmt in CI (ee2e1c2), closes #132
  • release: fall back to github.token when RELEASE_PLEASE_TOKEN is absent (7aa5d42), closes #131
  • remove claude issue-triage workflow (b70aa01)
  • remove dead build-telemetry OTEL config referencing non-existent secrets (03a748d), closes #133
  • remove notify-maintainer-on-new-issue workflow (91e343f)
  • renovate: track pinned syft / go-licenses versions via custom managers (65b3e38), closes #135
  • run extract_test.py parser-contract tests in the api-contract job (457802b), closes #136
  • security: narrow api-contract-enrich agent gh allowlist + document ingress (e34e288), closes #134
  • security: pin opnsense/docs SHA and parser pip deps in api-contract (b2cf72e), closes #130