Commit Graph
6924 Commits
Author SHA1 Message Date
jokob-sk 4a60a04e0d BE: stricter name resoltion #1731 2026-11-02 00:14:38 +11:00
jokob-sk 0e9fa668a3 BE: review fixes 2026-11-01 23:42:52 +11:00
jokob-sk 129ac8133b Merge branch 'next_release' of github.com:netalertx/NetAlertX into next_release 2026-11-01 23:24:10 +11:00
jokob-sk 03911713bb BE: watched fields notification fix #1865 2026-11-01 23:23:54 +11:00
Jokob @NetAlertX ce971aba45 Merge pull request #1869 from sebingel/fix/piholeapi-presence
PIHOLEAPI: use lastQuery for online status, do not mark offline imports as present
2026-11-01 21:09:14 +09:00
jokob-sk 20039a375e BE: performance charts fix #1866 2026-11-01 22:56:54 +11:00
jokob-sk 2b956866b8 BE: performance charts fix #1866 2026-11-01 22:56:45 +11:00
jokob-sk 7cdbaf23a8 Merge branch 'next_release' of github.com:netalertx/NetAlertX into next_release 2026-11-01 22:42:57 +11:00
jokob-sk 01c1603649 PLG: NBTSCAN parsing fix #1867 2026-11-01 22:42:39 +11:00
Jokob @NetAlertX f72ca7ff03 Merge pull request #1871 from sebingel/fix/piholeapi-verify-ssl
PIHOLEAPI: make the Verify SSL setting work and check setting keys
2026-11-01 20:13:34 +09:00
sebingel 0aa4536983 makes PIHOLEAPI report a failed TLS certificate check as such
With "Verify SSL" working, the login request checks the Pi-hole
certificate when that setting is on. In a live test with the setting on
and Pi-hole behind a reverse proxy with an untrusted certificate, the
login failed with "Connection error during Pi-hole auth. Check
PIHOLEAPI_URL and PIHOLEAPI_PASSWORD", although URL and password were
right. requests.exceptions.SSLError is a subclass of ConnectionError, so
the certificate error fell into that branch.

Changes:
- pihole_api_auth() catches requests.exceptions.SSLError before
  ConnectionError (server/plugins/pihole_api_scan/pihole_api_scan.py) and
  logs: "TLS certificate check failed during Pi-hole auth: <error>. Turn
  off PIHOLEAPI_VERIFY_SSL if Pi-hole uses a self-signed certificate."
- test/plugins/test_pihole_api_scan_verify_ssl.py: _login_failure() runs
  pihole_api_auth() with a failing login request.
  test_certificate_error_points_to_verify_ssl_setting checks the new
  message (fails without this change);
  test_plain_connection_error_still_points_to_url_and_password checks
  that other connection errors keep the old one.

Impact:
A user who turns on "Verify SSL" while Pi-hole uses a self-signed or
otherwise untrusted certificate gets a log line that names the cause and
the setting. Other connection errors are reported as before.
2026-11-01 09:33:41 +00:00
sebingel 71efcd0ba0 fixes PIHOLEAPI's ignored VERIFY_SSL setting and checks setting keys
main() read the setting 'PIHOLEAPI_SSL_VERIFY', but config.json defines
the function VERIFY_SSL, so the real key is PIHOLEAPI_VERIFY_SSL.
get_setting_value() returns "" for a key nobody defined, so every Pi-hole
API request got verify="": certificate checks were always off and the
InsecureRequestWarning was suppressed, even when a user had turned on
"Verify SSL". The login request sends the Pi-hole web password to
api/auth. The plugin README and docs/PIHOLE_GUIDE.md used the wrong name
too. test_plugin_conventions.py did not catch it: it only looks at
get_setting_value("X") or <literal>, and this line had no fallback.

Changes:
- test/plugins/test_plugin_conventions.py: new
  test_own_setting_keys_exist_in_config. Every literal
  get_setting_value('<PREFIX>_X') in a plugin's scripts must name a
  setting its own config.json defines; core settings and other plugins'
  keys are not checked. Before the fix it fails for exactly one of the 54
  plugins: pihole_api_scan.py, get_setting_value('PIHOLEAPI_SSL_VERIFY').
- New test/plugins/test_pihole_api_scan_verify_ssl.py: runs main() with
  VERIFY_SSL true and false and checks the verify= value that reaches
  requests.post() for api/auth. Only the HTTP call is mocked. It fails
  before the fix (verify=None).
- server/plugins/pihole_api_scan/pihole_api_scan.py: main() reads
  PIHOLEAPI_VERIFY_SSL.
- server/plugins/pihole_api_scan/README.md and docs/PIHOLE_GUIDE.md name
  the setting PIHOLEAPI_VERIFY_SSL.
- docs/PLUGINS_DEV.md, Conventions Checklist: read a setting under the
  exact key config.json defines; names the new check.

Impact:
"Verify SSL" now works. The default stays false, so default installs
behave as before. A user who turned it on while Pi-hole uses a
self-signed certificate will now see the login fail, as the setting
description says ("Disable if you are using a self-signed certificate").
Live check against Pi-hole v6.8 behind a proxy with an untrusted
certificate: with "Verify SSL" on the fixed code refused to log in, the
old code logged in and imported 33 entries.
2026-11-01 09:32:55 +00:00
sebingel b0575f33b8 points the plugin-review skill at PIHOLEAPI's lastQuery check
The plugin-review skill, in its section on per-row scanPresence, named
"pihole_api_scan's lastSeen-vs-threshold check" as a real implementation
to follow. Pi-hole FTL refreshes ips[].lastSeen for every client it holds
in memory, so that field is exactly the signal that kept devices online
for about 24 hours. A reviewer following the skill would have been sent
to the pattern that caused the bug.

Changes:
- .claude/, .gemini/ and .github/skills/plugin-review/SKILL.md, same edit
  in all three copies:
  - the example list says "last-activity timestamp" instead of
    "last-seen timestamp",
  - the reference points to pihole_api_scan's lastQuery-vs-threshold
    check, with the file path,
  - one added sentence: a timestamp the upstream keeps refreshing for
    every client it merely remembers is not a recency signal.

Impact:
Documentation for reviewers only. The three copies stay identical
(scripts/check_skill_pairs.py reports nothing for plugin-review).
2026-11-01 09:30:41 +00:00
sebingel 98f5b81cc8 marks PIHOLEAPI rows of offline devices as not present
With PIHOLEAPI_GET_OFFLINE enabled, PIHOLEAPI imports devices it considers
offline, but every row still counted as a live sighting. The plugin
computed the online state, yet never passed it on, and its config.json
mapped nothing to CurrentScan.scanPresence, so each row got the column
default 1. An offline device imported only for its name, vendor and IP
was marked online. ADGUARDIMP had the same problem in #1813 and fixed it
the same way.

Changes:
- main() passes the online state as helpVal4 '1' or '0' to add_object()
  (server/plugins/pihole_api_scan/pihole_api_scan.py).
- config.json maps helpVal4 to scanPresence, the same column definition
  adguard_import uses. The GET_OFFLINE description says offline devices
  are imported without being marked online; the README says the same.
- test/db_test_helpers.py: make_plugin_event_row() takes an optional
  help_val4, and CREATE_CURRENT_SCAN gets the
  CHECK (scanPresence IN (0, 1)) of the real schema (db_upgrade.py), so a
  test sees the same constraint as production.
- New test/scan/test_piholeapi_scan_presence_mapping.py runs the real
  PIHOLEAPI config.json through process_plugin_events() and checks that a
  helpVal4 '0' row lands in CurrentScan with scanPresence 0.
- test/plugins/test_pihole_api_scan.py: main() writes helpVal4 '0' for an
  offline device and '1' for every IP row of an online device. Both new
  tests fail without this change.

Impact:
Devices imported only because of PIHOLEAPI_GET_OFFLINE keep their name,
vendor and IP data but no longer mark the device as online. Live check
against Pi-hole v6.8: 28 rows with helpVal4 '0', 5 with '1'; the absent
phone got devPresentLastScan 0 and only a New Device event. With
GET_OFFLINE disabled (the default) every imported row is online, so
nothing changes there.
2026-11-01 09:29:50 +00:00
sebingel d15b682b51 makes PIHOLEAPI decide online status from the device lastQuery
Devices reported by PIHOLEAPI stayed online for about 24 hours after they
left the network (follow-up to #1436). The online check compared
PIHOLEAPI_CONSIDER_ONLINE with the freshest ips[].lastSeen of a device.
Pi-hole FTL v6.8 sets lastSeen to "now" on every network table update for
every client it still holds in memory, also when the client is not in the
ARP cache (src/database/network-table.c, add_FTL_clients_to_network_table()
calls add_netDB_network_address()). In a live run against Pi-hole v6.8 all
22 devices the old code reported as online had a lastSeen of 36 s, among
them a phone whose last DNS query was 18 h old.

Changes:
- New is_device_online(last_query, now_ts, consider_online) in
  server/plugins/pihole_api_scan/pihole_api_scan.py. A device is online if
  its last DNS query is at most consider_online seconds old; a lastQuery
  of 0 (never queried) is always offline.
- gather_device_entries() reads the device lastQuery instead of looping
  over ips[].lastSeen, and each entry carries 'isOnline'. The 'lastQuery'
  field (shown as "Last Query") now holds the real lastQuery.
- PIHOLEAPI_CONSIDER_ONLINE gets a module-level default of 300, like the
  other setting globals.
- The verbose line for a skipped offline device names the MAC and the
  age of its last DNS query instead of dumping the whole device dict.
- config.json: CONSIDER_ONLINE is labeled "Online if last query" and its
  description says the window applies to the last DNS query.
- README: lists "Time of the last DNS query" and explains that online
  status comes from DNS activity, that quiet devices can show as offline,
  and what to do (presence scanner on the same schedule, or a larger
  CONSIDER_ONLINE when PIHOLEAPI is the only presence source).
- New test/plugins/test_pihole_api_scan.py (module stubs as in
  test_adguard_import.py): the reported case, the CONSIDER_ONLINE
  boundary, clock skew, a missing or zero lastQuery, a device with two
  IPs. All 10 tests fail on the old code.

Impact:
A device goes offline in PIHOLEAPI CONSIDER_ONLINE seconds after its last
DNS query, not about 24 hours later. Behavior change: a device that is on
but sends no DNS query within that window is not reported as online by
PIHOLEAPI any more. Setting keys and defaults are unchanged.
2026-11-01 09:29:02 +00:00
jokob-sk eeb7d070b4 BE: review fixes 2026-10-27 18:00:20 +11:00
jokob-sk 96f63ecc54 BE: review fixes 2026-10-27 15:06:30 +11:00
jokob-sk 03c8cace8a BE+FE: hardening 2026-10-27 14:19:55 +11:00
jokob-sk 32eeb327c2 NMAPDEV defalts fix #1852 2026-10-23 12:48:16 +11:00
Jokob @NetAlertX 8fe3b49507 Merge pull request #1860 from netalertx/main
sync
2026-10-23 10:24:47 +09:00
Jokob @NetAlertX f669502028 Merge pull request #1858 from mauricio-camayo/fix/sync-hub-node-name
Sync + WIFICANARY: attribute synced detections to their node
v26.10.24
2026-10-23 10:21:22 +09:00
jokob-sk ddc7cc67be PR cleanup alpine and python bump 2026-10-23 12:10:42 +11:00
Jokob @NetAlertX 212e0d3a6d Merge pull request #1859 from netalertx/main
sync
2026-10-23 10:05:51 +09:00
Jokob @NetAlertX 7e8f24aaa7 Merge pull request #1855 from frdmn/fix/mcp-sse-relative-endpoint
fix(mcp): advertise a relative SSE endpoint so clients work behind the /server proxy
2026-10-23 10:02:26 +09:00
Jokob @NetAlertX e9bb6a84bc Merge pull request #1857 from RobinMJD/fix/php-security-alpine-3.24
fix(docker): require patched PHP 8.3 on Alpine 3.24
2026-10-23 10:01:05 +09:00
Mauricio CamayoandClaude Opus 5.5 c263e939fd Address review: docstrings for execute_plugin and new WIFICANARY tests
execute_plugin's leading description comment becomes a docstring, as it
was touched by this PR; the two new check_trusted_aps tests get
docstrings instead of leading comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PzCQWQVz9b2UzqLiGp2mPM
2026-10-22 12:29:12 -05:00
Mauricio CamayoandClaude Opus 5.5 ca4e92c32d Sync + WIFICANARY: attribute synced detections to their node
Fixes found running WIFICANARY on a WiFi satellite node that pushes its
detections to a hub with no WiFi of its own.

Synced plugin objects were stored with syncHubNodeName = "decoded"
instead of the node's name. plugin.py took filename.split(".")[2], but by
the time the hub processes the file decode_and_rename_files() has renamed
it to last_result.<PREFIX>.decoded.<NodeName>.<N>.log, so index 2 is the
literal marker. The parsing now lives in
utils.plugin_utils.get_sync_hub_node_name(), next to the function that
produces these names; it keeps node names that contain dots and returns
"" for local result files.

WIFICANARY's absent_baseline_clone was evaluated per trusted_aps entry,
so with a main AP + range extender pair, a weak clone seen while only the
main AP was in range also raised absent_baseline_clone through the
extender's entry, on top of the correct evil_twin. The baseline now
counts as present if any trusted radio for that SSID is visible;
single-entry behaviour is unchanged.

Leaving WIFICANARY_IFACE blank is how such a hub ingests the node's
detections (core processes the synced files after the plugin runs), but
it logged an unconditional "not set - nothing to scan" every cycle. It is
now a verbose "hub-only mode" message, and the node + hub setup is
documented in the setting description and the plugin README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PzCQWQVz9b2UzqLiGp2mPM
2026-10-22 12:09:53 -05:00
RobinMJD 90b1c081c8 fix(docker): require patched PHP 8.3 on Alpine 3.24
Move the Alpine builder and runner to the supported community repository, require PHP 8.3.36 or newer for the installed runtime components, and keep the Python 3.14 import paths aligned in the generated devcontainer. Add a runtime regression check for CLI, FPM and CGI covering CVE-2026-109618 and CVE-2026-109619.
2026-10-22 00:32:28 +02:00
Jonas Friedmann 68aaeaf527 BE+TESTS: relative MCP SSE endpoint path #1854
The SSE endpoint event advertised the absolute path /mcp/messages, which drops the /server prefix when clients connect through the bundled nginx proxy on port 20211. Clients then POST to /mcp/messages, nginx serves it as a static file and returns 404, so MCP clients can't connect via the proxy. A relative path resolves against whichever SSE URL the client used, so it works both directly and behind the prefix.
2026-10-21 13:07:34 +02:00
anton garcias 32e2ddd322 Translated using Weblate (Catalan)
Currently translated at 99.7% (864 of 866 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ca/
2026-10-19 19:51:21 +02:00
jokob-sk 10eea5603e BE: down notifications offset issue #1851 2026-10-19 19:11:30 +11:00
jokob-sk fa51d35480 Merge branch 'next_release' of github.com:netalertx/NetAlertX into next_release 2026-10-19 19:11:09 +11:00
jokob-sk e9747066f1 BE: down notifications offset issue #1851 2026-10-19 19:10:46 +11:00
jokob-sk fbb42fbc61 BE: down notifications offset issue #1851 2026-10-19 19:10:30 +11:00
Jokob @NetAlertX b03a292aa3 Merge pull request #1850 from netalertx/main
sync
2026-10-19 08:06:28 +11:00
jokob-sk 7bb7ce9c8d DOCS: permissions on Synology 2026-10-19 08:05:33 +11:00
Jokob @NetAlertX fe29f5d481 Merge pull request #1849 from Clearmist/patch-1
Fix duplicate content in DOCKER_COMPOSE.md
2026-10-19 07:02:03 +11:00
Clearmist 0149eaaa72 Fix duplicate content in DOCKER_COMPOSE.md
Removed duplicate sentence about configuring docker-compose.
2026-10-18 07:23:57 +00:00
jokob-sk 86ac9c3b2f Merge branch 'next_release' of github.com:netalertx/NetAlertX into next_release 2026-10-18 10:25:35 +11:00
jokob-sk e8c214dda9 PLG: INTERNET plugin fix #1845 2026-10-18 10:25:23 +11:00
Jokob @NetAlertX 543464c2d9 Merge pull request #1848 from netalertx/main
sync
2026-10-18 10:06:51 +11:00
jokob-sk 02557f0db5 PLG: INTERNET plugin fix #1845 2026-10-18 10:01:18 +11:00
mid 4dcfed9b80 Translated using Weblate (Japanese)
Currently translated at 100.0% (866 of 866 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-10-16 11:51:28 +02:00
Safeguard 6da7fa1665 Translated using Weblate (Russian)
Currently translated at 100.0% (866 of 866 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-10-16 11:51:25 +02:00
Jokob @NetAlertX 7dd399abd9 Merge pull request #1844 from netalertx/main
sync
2026-10-14 13:01:24 +11:00
Massimo Pissarello 11280a19c3 Translated using Weblate (Italian)
Currently translated at 100.0% (866 of 866 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-10-14 02:51:21 +02:00
Jokob @NetAlertX 290ceae0d3 Merge pull request #1843 from netalertx/next_release
Next release
2026-10-14 10:17:24 +11:00
jokob-sk 7795037843 FE: Hardening 2026-10-13 16:54:18 +11:00
Jokob @NetAlertX 90f2714639 Merge pull request #1842 from netalertx/main
Merge pull request #1837 from netalertx/next_release
2026-10-13 08:08:30 +11:00
Jokob @NetAlertX 12794ee111 Merge pull request #1837 from netalertx/next_release
BE+FE: Plugins -> Sources DevDetails tab
2026-10-13 08:07:51 +11:00