Owner request: finding where a host is plugged in from a MAC or IP is a must,
and BGP peer monitoring is wanted.
L2 job (internal/l2): a job of its own, off the 60 s poll path (its sessions
are path "l2"), walks BRIDGE-MIB, Q-BRIDGE-MIB, CISCO-VTP-MIB (a per-VLAN
context walk, enabled by the cisco-ios profile flag l2.per_vlan_context, not by
detection) and the IP-MIB neighbour tables (IPv4 ARP and IPv6 ND, IPv4-only
fallback) every l2.interval, with its own concurrency cap and a per-device
deadline. It yields to the poller like the rollup job, and a device that times
out is skipped for the cycle, counted and named on /poller/health. Migration 14
adds fdb_entries, arp_entries, vlans and l2_walks with first/last-seen history,
batched upserts, daily pruning by last_seen (l2.keep) and backup coverage.
API (additive): /l2/search ranks edge ports first (a port is an uplink above
l2.edge_max_macs MACs, with an LLDP neighbour, or as a LAG), plus the device
fdb/arp/l2/l2-ports tables and /interfaces/{id}/macs; vendor and mac_kind are
computed at query time from the optional registry.
BGP: profiles label peer rows by decoding the table index (index_label.layout),
so each peer, IPv4 or IPv6, is one component whatever MIB feeds it; AS, local
AS, router id and description are component attributes, never labels.
CISCO-BGP4 (cisco-ios, cisco-nxos), Juniper BGP4-V2 and Arista BGP4V2 replace
the optional generic BGP4-MIB metrics, which edgeos, fortigate, pfsense and vyos
switch on. /bgp/peers lists sessions down first. The built-in rule
bgp_peer_down (critical, not established for 2 minutes) fires only where a
policy binds it; its notification names the peer's AS and description.
Fixtures are generated (Q-BRIDGE with IPv4/IPv6 neighbours, BRIDGE-MIB only,
Cisco per-VLAN contexts via a new simagent contexts feature) and checked
against real LibreNMS recordings. DEVIATIONS 50-55 record the departures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T4PdJUPrakM8fHvN8jYv2x
162 lines
5.3 KiB
YAML
162 lines
5.3 KiB
YAML
# Enforces docs/MAINTAINABILITY.md. A hard rule: `make lint` must be clean for any gate to pass.
|
|
version: "2"
|
|
|
|
run:
|
|
timeout: 10m
|
|
tests: true
|
|
|
|
# Report every finding: funlen and gocognit flag the same line and must both show.
|
|
issues:
|
|
max-issues-per-linter: 0
|
|
max-same-issues: 0
|
|
uniq-by-line: false
|
|
|
|
linters:
|
|
default: none
|
|
enable:
|
|
- govet
|
|
- errcheck
|
|
- staticcheck
|
|
- unused
|
|
- ineffassign
|
|
- funlen
|
|
- cyclop
|
|
- gocognit
|
|
- nestif
|
|
- dupl
|
|
- lll
|
|
- errorlint
|
|
- usestdlibvars
|
|
- misspell
|
|
- revive
|
|
- depguard
|
|
- forbidigo
|
|
- nolintlint
|
|
- unconvert
|
|
- bodyclose
|
|
- copyloopvar
|
|
|
|
settings:
|
|
funlen:
|
|
lines: 80
|
|
statements: 50
|
|
ignore-comments: true
|
|
cyclop:
|
|
max-complexity: 15
|
|
gocognit:
|
|
min-complexity: 20
|
|
nestif:
|
|
min-complexity: 4
|
|
dupl:
|
|
threshold: 150
|
|
lll:
|
|
line-length: 140
|
|
misspell:
|
|
# MikroTik's OS name and a profile name, not a typo of "routers".
|
|
ignore-rules: [routeros]
|
|
nolintlint:
|
|
require-explanation: true
|
|
require-specific: true
|
|
revive:
|
|
rules:
|
|
- name: exported
|
|
arguments: ["disableStutteringCheck"]
|
|
- name: package-comments
|
|
- name: var-naming
|
|
- name: indent-error-flow
|
|
- name: error-strings
|
|
- name: receiver-naming
|
|
- name: unexported-return
|
|
forbidigo:
|
|
analyze-types: true
|
|
forbid:
|
|
- pattern: '^time\.(Now|Sleep|After|Tick|NewTicker|NewTimer)$'
|
|
msg: "use internal/clock so tests control time (docs/MAINTAINABILITY.md)"
|
|
depguard:
|
|
rules:
|
|
orm-only-in-store:
|
|
files: ["$all", "!**/internal/store/**"]
|
|
deny:
|
|
- pkg: github.com/uptrace/bun
|
|
desc: SQL and the ORM live only in internal/store
|
|
- pkg: database/sql
|
|
desc: SQL lives only in internal/store
|
|
app-only-from-cmd:
|
|
files: ["$all", "!**/cmd/**"]
|
|
deny:
|
|
- pkg: github.com/v10networks/nmon/internal/app
|
|
desc: only cmd/* wires the application
|
|
api-only-from-app:
|
|
files: ["$all", "!**/internal/app/**", "!**/internal/api/**", "!$test"]
|
|
deny:
|
|
- pkg: github.com/v10networks/nmon/internal/api
|
|
desc: only internal/app mounts the API
|
|
collection-paths-independent:
|
|
files:
|
|
- "**/internal/poller/**"
|
|
- "**/internal/discovery/**"
|
|
- "**/internal/traps/**"
|
|
- "**/internal/ingest/**"
|
|
- "**/internal/checks/**"
|
|
- "**/internal/rollup/**"
|
|
- "**/internal/alert/**"
|
|
- "**/internal/l2/**"
|
|
deny:
|
|
- pkg: github.com/v10networks/nmon/internal/poller
|
|
desc: collection paths share code via a lower package, not each other
|
|
- pkg: github.com/v10networks/nmon/internal/discovery
|
|
desc: collection paths share code via a lower package, not each other
|
|
- pkg: github.com/v10networks/nmon/internal/traps
|
|
desc: collection paths share code via a lower package, not each other
|
|
- pkg: github.com/v10networks/nmon/internal/l2
|
|
desc: collection paths share code via a lower package, not each other
|
|
devtools-not-in-nmon:
|
|
# The product binary never links dev/test machinery. `nmon profile record` needs only the
|
|
# .snmprec format, which lives in internal/snmprec.
|
|
files: ["**/cmd/nmon/**", "!$test"]
|
|
deny:
|
|
- pkg: github.com/v10networks/nmon/internal/simagent
|
|
desc: the simulator belongs to cmd/nmon-devtools and tests, never the shipped binary
|
|
- pkg: github.com/v10networks/nmon/internal/fixturegen
|
|
desc: the fixture generator belongs to cmd/nmon-devtools and tests, never the shipped binary
|
|
- pkg: github.com/v10networks/nmon/internal/fixtures
|
|
desc: fixtures are test data, never the shipped binary
|
|
- pkg: github.com/v10networks/nmon/internal/testutil
|
|
desc: test helpers are never in the shipped binary
|
|
devtools-no-core:
|
|
files: ["**/cmd/nmon-devtools/**"]
|
|
deny:
|
|
- pkg: github.com/v10networks/nmon/internal/app
|
|
desc: nmon-devtools talks to a running nmon over HTTP
|
|
- pkg: github.com/v10networks/nmon/internal/api
|
|
desc: nmon-devtools talks to a running nmon over HTTP
|
|
importer-not-in-nmon:
|
|
files: ["**/cmd/nmon/**"]
|
|
deny:
|
|
- pkg: github.com/v10networks/nmon/internal/librenms
|
|
desc: the LibreNMS importer is a separate tool (DEVIATIONS 9)
|
|
|
|
exclusions:
|
|
paths:
|
|
- web/node_modules
|
|
rules:
|
|
# Table-driven tests are long by nature; every other linter still applies.
|
|
- path: _test\.go
|
|
linters: [funlen, cyclop, gocognit, nestif, dupl, lll, forbidigo]
|
|
# The clock package wraps time; cmd/ and the test-only simulator may use real time.
|
|
- path: internal/clock/
|
|
linters: [forbidigo]
|
|
- path: cmd/
|
|
linters: [forbidigo]
|
|
# A package is allowed to import itself's own test helpers and itself.
|
|
- path: internal/(poller|discovery|traps)/.*_test\.go
|
|
linters: [depguard]
|
|
|
|
formatters:
|
|
enable:
|
|
- gofmt
|
|
- goimports
|
|
exclusions:
|
|
paths:
|
|
- web/node_modules
|