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
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.
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.
Add a standalone fixture using the real topology renderer and styles.
Check painted pixels in WebKit, Chromium and Firefox because DOM bounds
can remain correct when WebKit paints foreignObject content incorrectly.
Exercise node clicks, collapse/expand, wheel zoom and drag pan, including
assertions that pointer gestures change the SVG transform.
Document dependency installation and execution separately from pytest.
The regression fails with the original frontend and passes with the fix.
Keep encode_python_string() in front/php/server/util.php, replacing
encode_single_quotes() in place, and remove the standalone
app_conf_encode.php helper file and its require.
Rework the regression test to dispatch the real util.php savesettings
path through the PHP CLI against temporary synthetic config, API and
session directories, covering both scalar string and array string
settings: the generated app.conf must compile with warnings as errors
and parse back to the typed values.
The existing {s-quote} lifecycle is preserved (single quotes are still
written as {s-quote} and converted back by the same consumers), and the
app.conf readers in initialise.py and plugin_helper.py are unchanged.
app.conf is written by util.php saveSettings() as Python source and later
compiled/exec'd by the backend. String settings were emitted into
single-quoted Python literals with only ' encoded (as {s-quote}), so
backslashes were written raw. A regex such as 192\.0\.2\..* then produced
"SyntaxWarning: invalid escape sequence '\.'", valid Python escapes such as
\n were silently reinterpreted, and a trailing backslash made the file fail
to compile.
Move the encoder into a side-effect-free helper, app_conf_encode.php, as
encode_python_string(). It now doubles backslashes before the existing
{s-quote} replacement, so backslashes round-trip unchanged through app.conf
serialization and Python parsing, while single quotes keep using the legacy
{s-quote} placeholder. Both scalar string and array string serialization use
the helper.
Add regression tests that run the real PHP helper through the PHP CLI,
compile the generated source with warnings promoted to errors, and check
the scalar and array round trips.