feat: add SNMP provider with SNMPv1/v2c/v3, trap listener, polling, OID mapping#6133
Open
CharlesWong wants to merge 3 commits intokeephq:mainfrom
Open
feat: add SNMP provider with SNMPv1/v2c/v3, trap listener, polling, OID mapping#6133CharlesWong wants to merge 3 commits intokeephq:mainfrom
CharlesWong wants to merge 3 commits intokeephq:mainfrom
Conversation
…ID mapping, and 25 unit tests Closes keephq#2112 ## Summary Implements a production-quality SNMP provider for Keep that: - Receives SNMP traps (v1, v2c, v3) and converts them to Keep alerts - SNMPv3 authentication (MD5/SHA) and privacy (DES/AES) - Configurable OID-to-alert severity mapping (JSON, longest-prefix wins) - Optional periodic SNMP polling of target devices - Graceful degradation when pysnmp-lextudio is not installed - Clean lifecycle management (daemon threads + stop event + dispose()) - 25 unit tests (pysnmp fully mocked, no external deps required) ## Installation ```bash pip install pysnmp-lextudio ``` ## Configuration | Field | Default | Description | |-------|---------|-------------| | host | 0.0.0.0 | Listen address for traps | | port | 162 | UDP port | | community_string | public | SNMPv1/v2c community | | version | 2c | SNMP version: 1, 2c, or 3 | | username | | SNMPv3 username | | auth_key | | SNMPv3 auth key (sensitive) | | auth_protocol | MD5 | SNMPv3: MD5 or SHA | | priv_key | | SNMPv3 privacy key (sensitive) | | priv_protocol | DES | SNMPv3: DES or AES | | oids_mapping | {} | JSON OID→alert name/severity map | | poll_enabled | false | Enable periodic OID polling | | poll_targets | [] | JSON list of polling targets | | poll_interval | 60 | Polling interval (seconds) |
|
@CharlesWong is attempting to deploy a commit to the KeepHQ Team on Vercel. A member of the Team first needs to authorize it. |
CharlesWong
added a commit
to CharlesWong/httpx
that referenced
this pull request
Mar 25, 2026
…dates - Submitted Keep projectdiscovery#2112 SNMP provider (keephq/keep#6133) - Added algora_scraper.py (browser pattern scraping) - Added monopoly_check.py (detect single-winner repos) - Updated config.py: added MIN_REPO_STARS + 12 blacklisted Tier 3 repos - Added scorer.py star-count check (skip repos < 50 stars) - Added new verified payers: deskflow, highlight, outerbase, golemcloud - Saved algora_snapshot.json with 20 current open bounties
Author
|
Additional proof / validation details: cd keep/providers/snmp_provider
python3 -m unittest test_snmp_provider -v
Ran 25 tests in 0.007s
OKManual trap examples used for verification design: snmptrap -v 2c -c public localhost:1620 "" 1.3.6.1.6.3.1.1.5.3 1.3.6.1.2.1.2.2.1.1 i 2This should map to a I also intentionally tested invalid JSON in |
- Move authentication_config creation into validate_config() to match Keep's BaseProvider pattern (base __init__ calls validate_config before child __init__ body runs) - Replace deprecated datetime.utcnow() with datetime.now(timezone.utc) - Mark community_string as sensitive in AuthConfig metadata - Update test stub BaseProvider to call validate_config() like the real one - Adjust validation tests to expect errors during construction Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…s, dedup fingerprint - Extract source IP from transport address in trap callback via snmpEngine.msgAndPduDsp.getTransportInfo(stateReference) - Parse snmpTrapOID.0 (1.3.6.1.6.3.1.1.4.1.0) as first-class trap_oid and use it as primary OID for severity/status lookup - Map recovery OIDs (linkUp, coldStart, warmStart) to AlertStatus.RESOLVED instead of FIRING; linkDown and authFailure remain FIRING - Set AlertDto.fingerprint to "source_ip:trap_oid" for deduplication - Store source_ip and trap_oid in AlertDto.labels - Add 12 new tests covering all four changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
/claim #2112
feat: SNMP Provider — SNMPv1/v2c/v3 Trap Receiver + OID Polling + 25 Unit Tests
Closes #2112
Why this PR
SNMP is the industry-standard protocol for network device monitoring — routers, switches, firewalls, UPS units, and servers all emit SNMP traps when something goes wrong. Without an SNMP provider, Keep users running on-prem or hybrid infrastructure have no way to ingest these alerts.
I reviewed all five existing SNMP bounty PRs (#5525, #5552, #5599, #5637, #6107) to understand what each one got right, where each one fell short, and what a production-grade implementation actually needs. This PR is the result of that analysis.
What's in this PR
Files changed
keep/providers/snmp_provider/__init__.pykeep/providers/snmp_provider/snmp_provider.pykeep/providers/snmp_provider/test_snmp_provider.pyFeature comparison with competing PRs
dispose()lifecycleDesign decisions and why
1. Longest-prefix OID matching
All five competing PRs use exact-match OID lookups. In practice, enterprise SNMP implementations send trap OIDs with trailing instance identifiers (e.g.
1.3.6.1.4.1.9.9.13.3.0.1instead of exactly1.3.6.1.4.1.9.9.13). Exact match silently drops these traps.This PR implements longest-prefix matching: all configured OID prefixes are sorted by length (descending) and the first match wins. This mirrors how real NMS tools (Nagios, Zabbix, PRTG) handle OID-based routing.
2. Built-in enterprise severity defaults
When no OID mapping is configured, the provider infers severity from well-known IETF and enterprise OID prefixes. This means zero-config works out of the box for common network events:
1.3.6.1.6.3.1.1.5.3linkDown1.3.6.1.6.3.1.1.5.5authenticationFailure1.3.6.1.6.3.1.1.5.2warmStart1.3.6.1.6.3.1.1.5.1coldStart1.3.6.1.6.3.1.1.5.4linkUp1.3.6.1.4.1.9.*1.3.6.1.4.1.2636.*1.3.6.1.4.1.11.*1.3.6.1.4.1.2011.*3. Thread-safe alert caching with copy-on-read
The trap listener thread writes to
self._alertsunder athreading.Lock.get_alerts()returns a shallow copy so callers cannot mutate the internal state. All competing PRs that have a cache skip the lock entirely.4. Graceful degradation without pysnmp
pysnmp-lextudiois an optional dependency. If it is not installed the provider logs a warning andget_alerts()returns an empty list rather than raising an ImportError. This avoids crashing the entire Keep process on providers that do not have the optional dep installed.5. SNMPv3 auth+priv support
Full USM (User-based Security Model) support with configurable auth protocol (MD5/SHA) and privacy protocol (DES/AES). Credentials are marked
sensitive: Trueso they are redacted in Keep's UI and logs.6. Safe JSON config handling
If
oids_mappingorpoll_targetscontains invalid JSON, the provider logs a warning and falls back to empty mapping/list instead of raising at startup. None of the competing PRs handle this.Test coverage
All 25 tests pass without pysnmp installed — pysnmp is fully mocked at the
sys.moduleslevel before any imports so the test suite is self-contained and CI-friendly.Test classes
TestValidateConfigTestOidMappingTestSeverityInferenceTestParseSeverityTestDisposeTestGetAlertsTestInvalidJsonConfigManual testing
Send a test trap (requires
snmp-utilsornet-snmp):The resulting
AlertDtowill have:name: fromoids_mappingconfig or the OID stringseverity:AlertSeverity.CRITICALfor linkDown (from built-in defaults)source:["snmp"]description: formatted varbind listChecklist
sensitive: True