- core.py: add _BotAdminServer daemon thread (Flask, 127.0.0.1 only,
bearer token auth); POST /api/admin/reload calls reload_config() and
returns JSON {success, message}; GET /api/admin/health; started from
start() when [Admin] enabled = true and token is set
- scripts/reload_config.sh: curl wrapper for the reload API; reads
port/token from config.ini [Admin] section; exits 1 on rejection
- tests/test_core.py: TestBotAdminServer — 7 tests covering server
creation, missing token guard, reload success/failure/auth, health
Clean up residual cherry-pick conflict markers and keep SMTP guidance in config templates brief while preserving full behavior in code and tests.
Made-with: Cursor
Two incompatibilities surfaced after rebasing onto upstream/dev in code
introduced by #147:
- tests/integration/test_flood_scope_reply.py: add bot.is_radio_zombie = False
mock; the zombie-detection guard added to send_channel_message in #147
causes the call to short-circuit without it, failing the scope assertion;
also removes unused `call` import
- modules/web_viewer/app.py: replace ~50-line inline _get_version_info()
with 5-line delegate to resolve_runtime_version(); removes now-unnecessary
import subprocess; the resolve_runtime_version import is now actually used
Do not merge until #147 is merged.
Two small incompatibilities surfaced after rebasing dev-kg7qin-changes
onto upstream/dev in code introduced by #138:
- message_handler.py: replace two remaining Optional[str] annotations
with str | None; the Optional import was removed during typing
modernization but two annotations in this module were missed
- command_manager.py: restore # noqa: F401 guard on PUBLIC_CHANNEL_KEY_HEX
re-export so ruff auto-fix does not silently remove it (imported by core.py)
Do not merge until #138 is merged.
Fix ruff violations (import sort, unused imports, whitespace) in
backup_database.py, generate_website.py, meshcore_bot.py,
migrate_webviewer_db.py, packet_capture_service.py, version_info.py,
scripts/config_tui.py, scripts/update_todos.py, and validate_config.py.
Fix mypy stale type-ignore and remove unused imports in test files.
Add is_radio_zombie/is_radio_offline mock attributes to command_manager
test fixtures to prevent truthy Mock early returns.
Add scripts/check_log_injection.py to scan for unsanitized variables in
log calls and fail CI if new violations are introduced. Baseline is
committed at zero violations after fixing all 26 pre-existing ones.
Update TESTING.md with instructions for running the check locally.
Add SSRF host validation to maintenance.py send_nightly_email and
scheduler.py send_zombie_alert_email using validate_external_url().
New allow_local_smtp config key permits private-IP SMTP for local
relay setups.
Add sanitize_name() to security_utils and apply it to all log calls
in message_handler, repeater_manager, path_command, solarforecast_command,
command_manager, and discord_bridge_service to prevent log injection.
Move nightly email logic from duplicate scheduler._send_nightly_email()
into the canonical maintenance.py implementation, removing the duplicate.
Update tests to call maintenance.send_nightly_email() directly.
Add validate_external_url allow_private parameter with support for
loopback, RFC1918, CGN, and link-local address ranges.
The send_channel_message test was leaving bot.is_radio_zombie as an
unset MagicMock attribute, which evaluates truthy and triggers the
zombie-state early return before flood scope logic runs.
Add bot.is_radio_zombie = False to the mock setup so the function
reaches the set_flood_scope call as intended.
ff7917e incorrectly changed all test patches from
`scheduler.maintenance.run_db_backup` to `scheduler._run_db_backup`,
and rewrote `_setup` to bypass the delegation architecture upstream uses.
- Restore `_setup` to use `scheduler.maintenance.get_maint` side_effect
- Restore all 6 tests to patch `scheduler.maintenance.run_db_backup`
- Add `patch.object(scheduler.maintenance, "_get_current_time")` to
`test_weekly_on_wrong_day_does_not_run` to prevent Monday flakiness
in UTC CI environments (maintenance captures `_get_current_time` as a
bound method, so patching only `scheduler.get_current_time` is not
sufficient)
- base.html: persistent danger banner appears on every web page when
is_radio_zombie is true; shows datetime zombie was detected; includes
"Restart Bot Processing" button (POST /api/admin/zombie-recover) that
clears _radio_zombie_detected and _radio_fail_count on the live bot
object and removes the persisted DB flag; banner turns green on success
- config.html: new "Zombie Radio Alert" card with enable/disable toggle
and alert-email field; "Save" writes to bot_metadata (immediate,
survives restarts); "Save to config.ini" also persists values to
config.ini and keeps the in-memory config in sync; card shows
current config.ini values as baseline defaults
- app.py: inject_template_vars context processor now provides
radio_zombie and radio_zombie_since to all templates; added
GET/POST /api/config/zombie-alert endpoints (GET returns both
bot_metadata and config.ini values; POST supports write_to_config
flag); added POST /api/admin/zombie-recover endpoint; stored
config_path on self for write-back use
- scheduler.py: send_zombie_alert_email now prefers bot_metadata
(zombie.alert_enabled, zombie.alert_email) over config.ini so web
UI changes take effect without a restart; uses isinstance(..., str)
guard so mock/None values safely fall through to config.ini defaults
When the radio firmware is unresponsive but not yet flagged as zombie,
send_advert() would hang indefinitely on the main event loop, blocking
all packet processing (no data in/out) for 60+ seconds until the
scheduler thread's future.result() timed out — but that only timed
out the waiting thread, not the coroutine itself.
Fix: wrap every send_advert() call that runs on the event loop with
asyncio.wait_for(timeout=30.0). On timeout in the interval-advert
path, _radio_fail_count is incremented so repeated timeouts feed into
the existing zombie-detection threshold.
- Updated `app.py` to ensure the project root is correctly added to `sys.path` when the script is executed directly, allowing for proper module imports.
- Removed redundant code that previously handled project root path insertion, streamlining the import process.
resolves issue of overriding command classes not honoring replies in channels
I had already implemented about 60% of this when your PR came in, so I adopted some of your pattern into my changes.
- Updated `config.ini.example` to introduce the `respond_to_mentions` setting, allowing configuration of how the bot responds to mentions in channel messages.
- Refactored `MessageHandler` to implement logic for handling mentions based on the new configuration, including stripping mentions when appropriate.
- Added `cleanup_message_for_matching` method in `BaseCommand` to streamline message processing and mention validation.
- Enhanced various command classes to utilize the new cleanup method for consistent mention handling.
- Introduced tests to validate the behavior of the new mention handling logic across different configurations.
Match firmware TC_FLOOD scope overhead in get_max_message_length via
MeshMessage.effective_outgoing_flood_scope; keep CommandManager and
BaseCommand in sync with tests.
Made-with: Cursor
- Updated `config.ini.example` to clarify the usage of `outgoing_flood_scope_override` and `flood_scopes`, providing examples for better understanding.
- Modified `configuration.md` to reflect changes in flood scope handling, emphasizing the distinction between `outgoing_flood_scope_override` and `flood_scopes`.
- Refactored `CommandManager` to utilize the new `outgoing_flood_scope_override` for sending messages, ensuring consistent scope handling.
- Enhanced `MessageHandler` to prioritize library-provided scope fields for improved accuracy in flood scope matching.
- Added tests to validate the handling of flood scope fields from library payloads, ensuring robustness in message processing.
- Updated `config.ini.example` to clarify password requirements for web viewer authentication, emphasizing the need for a password when binding to non-loopback interfaces.
- Introduced a new function `normalized_web_viewer_password` in `integration.py` to standardize password retrieval and validation, handling various empty and null placeholder cases.
- Enhanced error logging in `core.py` to use `logger.error` for web viewer integration failures, improving visibility of issues.
- Modified `app.py` to utilize the new password normalization function, ensuring consistent password handling across the application.
- Added tests in `test_web_viewer_integration.py` to validate password normalization and error logging behavior when the web viewer is configured without a password.
- Updated `config.ini.example` to include a warning about running the bot on the Public channel and added an override key for intentional usage.
- Enhanced `config_validation.py` to implement a public channel guard that prevents the bot from starting if the Public channel is included in monitored channels without the override.
- Refactored `CommandManager` and `Core` to check for the Public channel key during channel loading and connection setup, ensuring compliance with the new guard.
- Improved documentation in `configuration.md` and `config-validation.md` to clarify the implications of using the Public channel and the necessary configuration changes.
- Updated `config.ini.example` to clarify flood scope configuration, introducing the auto-hashtag format for region names and adding support for multi-scope replies.
- Refactored `ChannelManager` to improve handling of empty channels, adjusting timeout logic and increasing request delay to prevent overwhelming devices.
- Enhanced `CommandManager` to load flood scope keys for HMAC matching and normalize scope names for consistency.
- Implemented scope matching in `MessageHandler` to ensure replies respect configured flood scopes, improving message routing accuracy.
- Updated `MeshMessage` model to include a `reply_scope` attribute for tracking matched flood scopes.
- Increased the per-user rate limit from 5 to 30 seconds across multiple configuration files to reduce response frequency.
- Added the version command to the configuration examples and updated help text to include the new command.
- Refactored version information retrieval in the bot and web viewer to utilize a shared runtime resolver for consistency.
- Improved documentation in README.md to reflect changes in commands and configuration options.
- Refactored the logic for displaying multibyte path statistics in the doughnut chart, improving clarity and responsiveness.
- Introduced a function to disable animations for smoother updates when data changes.
- Updated chart options to dynamically reflect multibyte and other path data, enhancing user experience and visual representation.
These changes improve the accuracy and usability of the multibyte path statistics in the dashboard.
- Improved error handling for `out_path_hash_mode` and `out_path_len` to ensure proper type conversion and validation.
- Added logic to derive `out_path_len` from `out_path` when it is missing, enhancing robustness against incomplete data.
- Updated tests to verify correct behavior when `out_path_hash_mode` is provided as a string and `out_path_len` is absent.
- Introduced a new `CondensePathsMode` type to support multiple condensing styles: "off", "flat", and "nested".
- Updated `_condense_path_lines` to handle different condensing modes, improving path representation.
- Enhanced test coverage for path condensing scenarios, ensuring accurate output for various path configurations.
These changes improve the flexibility and usability of path handling in the MultitestCommand, allowing for better visualization of path structures.
- Changed the fallback value for condense_paths from False to True in the MultitestCommand class, ensuring that paths are condensed by default. This adjustment improves the command's usability and aligns with expected behavior.
- Added calculations for contacts and incoming packets with multibyte path evidence over the last 7 days in `app.py`, improving data accuracy.
- Introduced new methods for handling multibyte path chunks and counting packets from JSON data, enhancing backend functionality.
- Updated `contacts.html` and `index.html` templates to display multibyte path encoding badges and tooltips, improving user interface clarity.
- Enhanced CSS for path encoding badges to differentiate between multibyte and one-byte paths, ensuring better visual representation.
These changes improve the overall user experience and data representation in the Bot Data Viewer.
- Updated `config.ini.example` to include detailed MQTT weather configuration options, enhancing clarity and usability.
- Expanded JSON template placeholders in `mqtt_weather.py` to support additional weather data fields, improving data representation.
- Introduced new utility functions for better handling of numeric and non-negative integer values in payload formatting.
- Enhanced test coverage for MQTT weather functionality, ensuring robust handling of extended placeholders and configuration loading.
These changes improve the flexibility and reliability of the MQTT weather integration, allowing for more comprehensive weather data management.
- Added `libffi-dev` and `libssl-dev` to the first RUN command for enhanced support of cryptographic operations.
- Included `libffi8` in the second RUN command to ensure compatibility with specific libraries.
These changes optimize the Docker image for building applications that require these libraries.
- Changed single quotes to HTML entities in JSON placeholders within the feeds.html file to ensure proper rendering.
- Updated the assignment of PREFIX_HEX_CHARS in mesh.html to parse the value as an integer, enhancing type safety and clarity.
These changes enhance the user interface and code maintainability in the web viewer templates.
- Updated type hints to use `|` for union types instead of `Optional` where applicable, enhancing readability and consistency.
- Cleaned up import statements by removing unnecessary imports and organizing them for better clarity.
- Adjusted function signatures in various modules to reflect the new type hinting style, improving type safety and code maintainability.
These changes contribute to a more modern and consistent codebase, aligning with current Python typing practices.