0.8.0-dev8: second sensory publisher — Meraki webhook → NATS#9
Merged
Conversation
First webhook-side sensory publisher. The web process now publishes sensory.* events when Meraki Dashboard webhooks arrive, so a port flap detected at the network edge reaches the reflex pipeline in 50-200ms instead of waiting up to a full SNMP poll cycle (5 minutes). This is the first release where the dedup store added in dev3 actually does anything in production: the same port flap will now be observed by both the Meraki webhook (immediate) and the SNMP poller (next cycle), and the second arrival within the 60s dedup window collapses to a single :ReflexEvent. New abstractions (all swappable / additive): - webhooks/event_publisher.py: web-process bus coordination. One NatsEventBus per process; one cached SensoryPublisher per source. Graceful degradation when NATS_URL is unset. - webhooks/meraki_events.py: pure Meraki-dialect-to-our-taxonomy mapper. Initial coverage: Port connectivity (link_up/down), Switch port connection changed (synonym), Uplink status change, IDS alerted, Malware detected, Settings changed, Configuration change. - Target shape: meraki:<deviceSerial>|<portName> — matches Device.id in the live graph so the dev7 :AFFECTS edge resolver lands edges automatically. Wiring: - handle_meraki_webhook accepts optional publisher; runs mapper and publishes one event per mapped alert. Pre-dev8 sync-trigger behavior preserved when publisher absent. - main.py lifespan inits NATS bus on startup (best-effort), closes on shutdown. Web deployment already has NATS_URL via Helm. - Webhook response body adds sensory_events_published count for operator at-a-glance verification. Tests (28 new): - 18 mapper unit tests covering every supported alertType, both states, synonym handling, missing-field degradation, and a subject-builder compatibility smoke test. - 10 HTTP integration tests covering HMAC valid/invalid/missing, signature prefix variants, malformed JSON, no-secret degradation, unknown alertType, IDS publish, publisher-unavailable, and bus-failure-during-publish. - First FastAPI TestClient test module in the repo; pattern generalized via tests/webhooks/conftest.py for the dev9/10/11 vendor receivers to reuse. Co-authored-by: Cursor <cursoragent@cursor.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.
Summary
First webhook-side sensory publisher. The web process now publishes
sensory.*events when Meraki Dashboard webhooks arrive:A port flap detected at the Meraki edge now reaches Neo4j in 50–200ms instead of waiting up to a full SNMP poll cycle (5 minutes).
This is the first release where the dedup store added in 0.8.0-dev3 actually does anything in production. The same port flap will now be observed by both the Meraki webhook (immediate) and the SNMP poller (next cycle), and the second arrival within the 60s dedup window collapses to a single
:ReflexEvent.What landed
New
Changed
Tests (28 new)
Operational notes
```cypher
MATCH (e:ReflexEvent {source: 'meraki_webhook'})
WHERE e.recorded_at > timestamp() - 3600000
RETURN e.subject, e.target, e.outcome
ORDER BY e.observed_at_ms DESC
```
```cypher
MATCH (e1:ReflexEvent), (e2:ReflexEvent)
WHERE e1.target = e2.target
AND e1.source = 'meraki_webhook' AND e2.source = 'snmp_poll'
AND e1.event_class = e2.event_class
AND abs(e1.observed_at_ms - e2.observed_at_ms) < 60000
RETURN e1.target, e1.outcome AS webhook_outcome, e2.outcome AS snmp_outcome
```
Deferred to subsequent releases
Test plan
Made with Cursor