The custom header added in #1695 was a single name/value pair, which is
enough for a proxy that authenticates with one token but not for Pangolin,
which expects both P-Access-Token-Id and P-Access-Token.
NTFY_CUSTOMHEADER_NAME and NTFY_CUSTOMHEADER_VALUE are replaced by a single
list setting, NTFY_CUSTOM_HEADERS, holding one "Name: Value" entry per
header. The list widget is the same one the other list settings use.
Only the first colon separates the name from the value, so values may
contain colons. An entry is skipped and logged when it is malformed, when
the name repeats, or when it collides with a header the plugin already set,
so a custom header still cannot clobber the ntfy credentials.
Values are never written to the log, since they are usually secrets. That
also applies to the invalid-header error, which now names the headers that
were applied without quoting any of them.
- Replace max() with explicit if/else for readability
- Use db_test_helpers (make_db, make_device_dict, insert_device_from_dict,
DummyDB) instead of local mock DB objects in test_nic_presence.py
- Lowercase all MAC addresses in tests
Co-authored-by: jokob-sk <96159884+jokob-sk@users.noreply.github.com>
When a parent device has NIC children, update_devPresentLastScan_based_on_nics
previously replaced the parent's devPresentLastScan unconditionally with the
NIC-derived value. This discarded any genuine direct detection of the parent:
if the parent was found by ARP/save_own_device (present=1) but its NIC child
was absent (present=0), the NIC step forced the parent back to 0. The next
scan re-detected the parent → Connected event → NIC forced it down again,
producing an endless one-directional Connected event stream.
Fix: use max(original, nic_derived) so NIC children can only raise a parent's
presence (bring an undetected parent online), never lower it when the parent
itself was directly detected this cycle.
Adds test/scan/test_nic_presence.py covering the exact regression scenario
and surrounding cases (raise, no-NIC unchanged, req_all modes).
Fixes#1736
Co-authored-by: jokob-sk <96159884+jokob-sk@users.noreply.github.com>
- Introduced a new plugin for monitoring website health, including functionality to check URLs and log results.
- Created README and configuration files for the workflows plugin, detailing its purpose and settings.
- Updated import paths in various test files to reflect the new directory structure.
- Ensured compatibility of test cases with the updated plugin architecture.
- Added db_history.py to manage DevicesHistory table and triggers for INSERT and UPDATE operations.
- Created device_history_instance.py for querying and grouping DevicesHistory records.
- Developed change_history.php for displaying device change history with filtering and pagination.
- Introduced skel_device_details_tab_history.php for skeleton loading state in device details tab.
- Added unit tests in test_device_history.py to validate trigger functionality and history management.
- Implemented filter population and pagination in the change history UI.
- Changed the test suite name for clarity.
- Updated default behavior for running all tests in the workflow.
- Improved logging in the Docker test script for better debugging.
- Modified assertions in Nginx proxy security tests to ensure access is not blocked.
- Added exception handling in UI tests to skip tests when elements are not found.
- Implemented the REST Import plugin (rest_import.py) to handle importing data from REST APIs.
- Added functionality for configurable HTTP methods, authentication types, and custom headers.
- Included error handling for various HTTP response statuses and connection issues.
- Created unit tests for the plugin covering header building, path resolution, MAC validation, record mapping, and authentication methods.
- Ensured that module-level side effects are patched during tests to prevent live interactions.
- Added `queryByConditions` method to `DeviceInstance` for flexible device querying based on dynamic conditions.
- Introduced `interpolate_tokens` function to replace placeholders in action values with actual device data.
- Updated `UpdateFieldAction` to handle cross-device updates and archive conflicting MAC addresses.
- Implemented cascade prevention in `WorkflowManager` to avoid processing events for devices modified in the same batch.
- Added unit tests for new functionalities, including token interpolation, condition querying, and action execution.
- Created constants for device column validation to enhance security and maintainability.
- Established a structured research skill specification to guide development practices.
Replaces the raw sqlite3 query in get_netalertx_devices() with
DeviceInstance().getAll() as suggested in code review, applying the
archived/offline/new filters in Python. Removes the sqlite3 and
fullDbPath imports. Updates tests to mock DeviceInstance.getAll().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- config.json: add show:true to all visible column definitions so they
render in the plugin output table
- script.py: fix managed_names adoption bug — update/skip branches no
longer add unowned clients to managed state; rename tracking now
scoped to plugin-created clients only
- README.md: fix ADGUARDEXP_URL default (localhost:3000, not local IP),
add language tags to fenced code blocks, normalise metadata block to
Other info / Maintainer / DD-Mon-YYYY format
- test_adguard_export.py: add regression test for manual client matched
by ID not being adopted into managed state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new NetAlertX plugin that syncs known devices from the NetAlertX
database to AdGuard Home as persistent clients, keeping names, MACs, IP
addresses, and device-type tags in sync.
Also fixes the adguard_import config.json description placeholder and a
minor indentation inconsistency in that file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>