(ip, interface=DEFAULT_ARP_SCAN_INTERFACE)
| 1903 | # ========================================================================== |
| 1904 | |
| 1905 | _watchtower_lock = threading.Lock() |
| 1906 | _watchtower = None # lazy watchtower.Watchtower instance |
| 1907 | _wt_seen = {} # pushover dedup: key -> {'rank', 'ts'} |
| 1908 | _wt_seen_loaded = False |
| 1909 | _wt_summary = {'enabled': False, 'ts': None, 'total': 0} |
| 1910 | |
| 1911 | # Cross-signal correlation: fold the same normalized alert stream into |
| 1912 | # attack-chain *incidents* (see incident_engine.py). Paged once per incident when |
| 1913 | # it first becomes a named campaign or escalates. |
| 1914 | _incident_engine = None |
| 1915 | _inc_notified = {} # incident id -> {'pattern', 'severity'} |
| 1916 | _incidents_summary = {'total': 0, 'named': 0} |
| 1917 | |
| 1918 | |
| 1919 | def _inc_get(): |
| 1920 | global _incident_engine |
| 1921 | if _incident_engine is None: |
| 1922 | import incident_engine as _ie |
| 1923 | try: |
| 1924 | window = float(shared_data.config.get('incident_window_s', 600)) |
| 1925 | except (TypeError, ValueError): |
| 1926 | window = 600.0 |
no test coverage detected