diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4ab239c..6f2dc2c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -188,7 +188,7 @@ jobs: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-ingestor-linux-amd64:${{ steps.version.outputs.version }} docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-ingestor-linux-amd64:${{ steps.version.outputs.version_with_v }} docker run --rm --name ingestor-test \ - -e POTATOMESH_INSTANCE=http://localhost:41447 \ + -e INSTANCE_DOMAIN=http://localhost:41447 \ -e API_TOKEN=test-token \ -e CONNECTION=mock \ -e DEBUG=1 \ diff --git a/CHANGELOG.md b/CHANGELOG.md index b4e2119..d51895e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,65 @@ # CHANGELOG +## v0.6.0 + +**Breaking changes — remove deprecated environment variable aliases:** + +* Ingestor: remove `POTATOMESH_INSTANCE` env var — use `INSTANCE_DOMAIN` by @l5yth +* Ingestor: remove `PROVIDER` env var — use `PROTOCOL` by @l5yth +* Ingestor: remove `MESH_SERIAL` env var — use `CONNECTION` by @l5yth +* Ingestor: remove `PORT` config alias — use `CONNECTION` by @l5yth +* Docker: give `INSTANCE_DOMAIN` a default of `http://web:41447` in compose by @l5yth +* Chore: bump version to 0.6.0 across web, matrix bridge, and mobile app by @l5yth + +## v0.5.12 + +* Enh: surface meshcore role types (#680) by @l5yth in +* Chore: refactor codebase before meshcore release by @l5yth in +* [Meshcore] enh: short name should be 1st 4 hex digits of public key by @benallfree in +* Chore: update xcode deps by @benallfree in +* Chore: update mesh.sh to use requirements file by @benallfree in +* Data/meshcore: fix ble and enable tcp by @l5yth in +* Data: handle store_forward and router_heartbeat portnum by @l5yth in +* Feat: implement meshcore provider by @l5yth in +* Ci: update dependabot and codecov settings by @l5yth in +* Web: prepare release by @l5yth in +* App: only query meshtastic provider by @l5yth in +* Data: prepare ingestor for meshcore by @l5yth in +* Web: fix css issues by @l5yth in +* Web: prepare frontend for multi protocol by @l5yth in +* Feat: split device and power-sensor telemetry charts (#643) by @l5yth in +* Web: implement a 'protocol' field across systems by @l5yth in +* Fix upsert clearing node coordinates bug by @l5yth in +* Data: resolve circular dependency of deamon.py by @l5yth in +* Proposal: mesh provider pattern refactor by @benallfree in +* Build(deps): bump rustls-webpki from 0.103.8 to 0.103.10 in /matrix by @dependabot[bot]< in https://github.com/l5yth/potato-mesh/pull/649> +* Build(deps): bump quinn-proto from 0.11.13 to 0.11.14 in /matrix by @dependabot[bot]< in https://github.com/l5yth/potato-mesh/pull/646> + +## v0.5.11 + +* Chore: bump version to 0.5.11 by @l5yth in +* Web: limit horizontal size of dropdown by @l5yth in + +## v0.5.10 + +* Web: expose node stats in distinct api by @l5yth in +* Web: do merge channels by name by @l5yth in +* Web: do not merge channels by ID in frontend by @l5yth in +* Web: do not touch neighbor last seen on neighbor info by @l5yth in +* Ingestor: report self id per packet by @l5yth in +* Ci: fix docker compose and docs by @l5yth in +* Web: supress encrypted text messages in frontend by @l5yth in +* Federation: ensure requests timeout properly and can be terminated by @l5yth in +* Build(deps): bump bytes from 1.11.0 to 1.11.1 in /matrix by @dependabot[bot]< in https://github.com/l5yth/potato-mesh/pull/627> +* Matrix: config loading now merges optional TOML with CLI/env/secret inputs by @l5yth in +* Matrix: logs only non-sensitive config fields by @l5yth in +* Web: decrypted takes precedence by @l5yth in +* Add Apache 2.0 license headers to missing sources by @l5yth in +* Web: decrypt PSK-1 unencrypted messages on arrival by @l5yth in +* Web: daemonize federation worker pool to avoid deadlocks on stuck announcments by @l5yth in +* Web: add announcement banner by @l5yth in +* L5Y chore version 0510 by @l5yth in + ## v0.5.9 * Matrix: listen for synapse on port 41448 by @l5yth in diff --git a/DOCKER.md b/DOCKER.md index 6ef5f08..02923ac 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -13,16 +13,16 @@ will pull the latest release images for you. ## Images on GHCR -| Service | Image | -|----------|---------------------------------------------------------------------------------------------------------------| -| Web UI | `ghcr.io/l5yth/potato-mesh-web-linux-amd64:` (e.g. `latest`, `3.0`, `v3.0`, or `3.1.0-rc1`) | -| Ingestor | `ghcr.io/l5yth/potato-mesh-ingestor-linux-amd64:` (e.g. `latest`, `3.0`, `v3.0`, or `3.1.0-rc1`) | +| Service | Image | +|----------|----------------------------------------------------------------------------------------------------------------| +| Web UI | `ghcr.io/l5yth/potato-mesh-web-linux-amd64:` (e.g. `latest`, `0.6.0`, `v0.6.0`, or `0.7.0-rc1`) | +| Ingestor | `ghcr.io/l5yth/potato-mesh-ingestor-linux-amd64:` (e.g. `latest`, `0.6.0`, `v0.6.0`, or `0.7.0-rc1`) | Images are published for every tagged release. Stable builds receive both -semantic version tags (for example `3.0`) and a matching `v`-prefixed tag (for -example `v3.0`), plus a `latest` tag that tracks the newest stable release. +semantic version tags (for example `0.6.0`) and a matching `v`-prefixed tag (for +example `v0.6.0`), plus a `latest` tag that tracks the newest stable release. Pre-release tags (for example `-rc`, `-beta`, `-alpha`, or `-dev` suffixes) are -published only with their explicit version strings (`3.1.0-rc1` and `v3.1.0-rc1` +published only with their explicit version strings (`0.7.0-rc1` and `v0.7.0-rc1` in this example) and do **not** advance `latest`. Pin the versioned tags when you need a specific build. @@ -60,9 +60,8 @@ Additional environment variables are optional: | `CONNECTION` | `/dev/ttyACM0` | Serial device, TCP endpoint, or Bluetooth target used by the ingestor to reach the radio. | The ingestor posts to the URL configured via `INSTANCE_DOMAIN` (defaulting to -`http://web:41447` in the provided compose file) and still accepts -`POTATOMESH_INSTANCE` as a legacy alias when the primary variable is unset. Use -`CHANNEL_INDEX` to select a LoRa channel on serial or Bluetooth connections. +`http://web:41447` in the provided compose file). Use `CHANNEL_INDEX` to select +a LoRa channel on serial or Bluetooth connections. ## Docker Compose file diff --git a/README.md b/README.md index d3399a0..c4afee5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,10 @@ [![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/l5yth/potato-mesh/issues) [![Matrix Chat](https://img.shields.io/badge/matrix-%23potatomesh:dod.ngo-blue)](https://matrix.to/#/#potatomesh:dod.ngo) -A federated, Meshtastic-powered node dashboard for your local community. +[![Meshtastic](https://img.shields.io/badge/Meshtastic-supported-67ea94)](https://meshtastic.org) +[![MeshCore](https://img.shields.io/badge/MeshCore-supported-000000)](https://meshcore.co.uk) + +A federated, Meshtastic & Meshcore node dashboard for your local community. _No MQTT clutter, just local LoRa aether._ * Web dashboard with chat window and map view showing nodes, positions, neighbors, @@ -17,13 +20,15 @@ _No MQTT clutter, just local LoRa aether._ * Allows searching and filtering for nodes in map and table view. * Federated: _automatically_ froms a federation with other communities running Potato Mesh! + * Supports Meshtastic and Meshcore * Supplemental Python ingestor to feed the POST APIs of the Web app with data remotely. * Supports multiple ingestors per instance. + * Supports Meshtastic and Meshcore * Matrix bridge that posts Meshtastic messages to a defined matrix channel (no radio required). * Mobile app to _read_ messages on your local aether (no radio required). -Live demo for Berlin #MediumFast: [potatomesh.net](https://potatomesh.net) +Live demo for Berlin: [potatomesh.net](https://potatomesh.net) ![screenshot of the fourth version](./scrot-0.4.png) diff --git a/app/ios/Flutter/AppFrameworkInfo.plist b/app/ios/Flutter/AppFrameworkInfo.plist index 008e9ff..6c20d18 100644 --- a/app/ios/Flutter/AppFrameworkInfo.plist +++ b/app/ios/Flutter/AppFrameworkInfo.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.5.12 + 0.6.0 CFBundleSignature ???? CFBundleVersion - 0.5.12 + 0.6.0 MinimumOSVersion 14.0 diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 3e7395f..5c9e62c 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -1,7 +1,7 @@ name: potato_mesh_reader description: Meshtastic Reader — read-only view for PotatoMesh messages. publish_to: "none" -version: 0.5.12 +version: 0.6.0 environment: sdk: ">=3.4.0 <4.0.0" diff --git a/configure.sh b/configure.sh index aff888f..c923864 100755 --- a/configure.sh +++ b/configure.sh @@ -219,16 +219,6 @@ else sed -i.bak '/^INSTANCE_DOMAIN=.*/d' .env fi -# Migrate legacy connection settings and ensure defaults exist -if grep -q "^MESH_SERIAL=" .env; then - legacy_connection=$(grep "^MESH_SERIAL=" .env | head -n1 | cut -d'=' -f2-) - if [ -n "$legacy_connection" ] && ! grep -q "^CONNECTION=" .env; then - echo "♻️ Migrating legacy MESH_SERIAL value to CONNECTION" - update_env "CONNECTION" "$legacy_connection" - fi - sed -i.bak '/^MESH_SERIAL=.*/d' .env -fi - if ! grep -q "^CONNECTION=" .env; then echo "CONNECTION=/dev/ttyACM0" >> .env fi diff --git a/data/__init__.py b/data/__init__.py index 8576efd..2aa2b8c 100644 --- a/data/__init__.py +++ b/data/__init__.py @@ -18,7 +18,7 @@ The ``data.mesh`` module exposes helpers for reading Meshtastic node and message information before forwarding it to the accompanying web application. """ -VERSION = "0.5.12" +VERSION = "0.6.0" """Semantic version identifier shared with the dashboard and front-end.""" __version__ = VERSION diff --git a/data/mesh_ingestor/__init__.py b/data/mesh_ingestor/__init__.py index 4b5ac8d..f4af0b7 100644 --- a/data/mesh_ingestor/__init__.py +++ b/data/mesh_ingestor/__init__.py @@ -82,9 +82,6 @@ _CONFIG_ATTRS = { "_debug_log", } -# Legacy export maintained for backwards compatibility. -_CONFIG_ATTRS.add("PORT") - _INTERFACE_ATTRS = {"BLEInterface", "SerialInterface", "TCPInterface"} _QUEUE_ATTRS = set(queue.__all__) diff --git a/data/mesh_ingestor/config.py b/data/mesh_ingestor/config.py index ea420e5..e5849c9 100644 --- a/data/mesh_ingestor/config.py +++ b/data/mesh_ingestor/config.py @@ -17,9 +17,7 @@ from __future__ import annotations import os -import sys from datetime import datetime, timezone -from types import ModuleType from typing import Any DEFAULT_SNAPSHOT_SECS = 60 @@ -49,12 +47,11 @@ DEFAULT_ENERGY_SLEEP_SECS = float(6 * 60 * 60) DEFAULT_INGESTOR_HEARTBEAT_SECS = float(60 * 60) """Interval between ingestor heartbeat announcements.""" -CONNECTION = os.environ.get("CONNECTION") or os.environ.get("MESH_SERIAL") +CONNECTION = os.environ.get("CONNECTION") """Optional connection target for the mesh interface. When unset, platform-specific defaults will be inferred by the interface -implementations. The legacy :envvar:`MESH_SERIAL` environment variable is still -accepted for backwards compatibility. +implementations. """ SNAPSHOT_SECS = DEFAULT_SNAPSHOT_SECS @@ -67,13 +64,7 @@ DEBUG = os.environ.get("DEBUG") == "1" _KNOWN_PROTOCOLS = ("meshtastic", "meshcore") -# Prefer the canonical PROTOCOL env var; fall back to legacy PROVIDER for -# backwards compatibility with existing deployments. -_raw_protocol = ( - (os.environ.get("PROTOCOL") or os.environ.get("PROVIDER", "meshtastic")) - .strip() - .lower() -) +_raw_protocol = os.environ.get("PROTOCOL", "meshtastic").strip().lower() if _raw_protocol not in _KNOWN_PROTOCOLS: raise ValueError( f"Unknown PROTOCOL={_raw_protocol!r}. " @@ -84,12 +75,8 @@ PROTOCOL = _raw_protocol """Active ingestion protocol, selected via the :envvar:`PROTOCOL` environment variable. Accepted values are ``meshtastic`` (default) and ``meshcore``. -The legacy :envvar:`PROVIDER` environment variable is still accepted as a fallback. """ -PROVIDER = PROTOCOL -"""Deprecated alias for :data:`PROTOCOL`; kept for backwards compatibility.""" - def _parse_channel_names(raw_value: str | None) -> tuple[str, ...]: """Normalise a comma-separated list of channel names. @@ -137,16 +124,11 @@ ALLOWED_CHANNELS = _parse_channel_names(os.environ.get("ALLOWED_CHANNELS")) def _resolve_instance_domain() -> str: """Resolve the configured instance domain from the environment. - The ingestor prefers the :envvar:`INSTANCE_DOMAIN` variable for clarity and - compatibility with the web application. For deployments that still - configure the legacy :envvar:`POTATOMESH_INSTANCE` variable, the resolver - falls back to that value when no primary domain is set. + Reads the :envvar:`INSTANCE_DOMAIN` variable. When the value does not + contain a scheme, ``https://`` is prepended automatically. """ - instance_domain = os.environ.get("INSTANCE_DOMAIN", "") - legacy_instance = os.environ.get("POTATOMESH_INSTANCE", "") - - configured_instance = (instance_domain or legacy_instance).rstrip("/") + configured_instance = os.environ.get("INSTANCE_DOMAIN", "").rstrip("/") if configured_instance and "://" not in configured_instance: return f"https://{configured_instance}" @@ -173,9 +155,6 @@ _ENERGY_ONLINE_DURATION_SECS = DEFAULT_ENERGY_ONLINE_DURATION_SECS _ENERGY_SLEEP_SECS = DEFAULT_ENERGY_SLEEP_SECS _INGESTOR_HEARTBEAT_SECS = DEFAULT_INGESTOR_HEARTBEAT_SECS -# Backwards compatibility shim for legacy imports. -PORT = CONNECTION - def _debug_log( message: str, @@ -232,23 +211,3 @@ __all__ = [ "_INGESTOR_HEARTBEAT_SECS", "_debug_log", ] - - -class _ConfigModule(ModuleType): - """Module proxy that keeps connection aliases synchronised.""" - - def __setattr__(self, name: str, value: Any) -> None: # type: ignore[override] - """Propagate CONNECTION/PORT and PROTOCOL/PROVIDER assignments to both attributes.""" - - if name in {"CONNECTION", "PORT"}: - super().__setattr__("CONNECTION", value) - super().__setattr__("PORT", value) - return - if name in {"PROTOCOL", "PROVIDER"}: - super().__setattr__("PROTOCOL", value) - super().__setattr__("PROVIDER", value) - return - super().__setattr__(name, value) - - -sys.modules[__name__].__class__ = _ConfigModule diff --git a/docker-compose.yml b/docker-compose.yml index 4ebbf44..88468cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,8 +52,7 @@ x-ingestor-base: &ingestor-base ALLOWED_CHANNELS: ${ALLOWED_CHANNELS:-""} HIDDEN_CHANNELS: ${HIDDEN_CHANNELS:-""} API_TOKEN: ${API_TOKEN} - INSTANCE_DOMAIN: ${INSTANCE_DOMAIN} - POTATOMESH_INSTANCE: ${POTATOMESH_INSTANCE:-http://web:41447} + INSTANCE_DOMAIN: ${INSTANCE_DOMAIN:-http://web:41447} DEBUG: ${DEBUG:-0} FEDERATION: ${FEDERATION:-1} PRIVATE: ${PRIVATE:-0} diff --git a/matrix/Cargo.lock b/matrix/Cargo.lock index 3f5ee84..59e3168 100644 --- a/matrix/Cargo.lock +++ b/matrix/Cargo.lock @@ -969,7 +969,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "potatomesh-matrix-bridge" -version = "0.5.12" +version = "0.6.0" dependencies = [ "anyhow", "axum", diff --git a/matrix/Cargo.toml b/matrix/Cargo.toml index 3c7b0c9..8082a0b 100644 --- a/matrix/Cargo.toml +++ b/matrix/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "potatomesh-matrix-bridge" -version = "0.5.12" +version = "0.6.0" edition = "2021" [dependencies] diff --git a/tests/dump.py b/tests/dump.py index 5d5e62d..f4dfc0c 100644 --- a/tests/dump.py +++ b/tests/dump.py @@ -28,9 +28,7 @@ from meshtastic.mesh_interface import MeshInterface from meshtastic.serial_interface import SerialInterface from pubsub import pub -CONNECTION = os.environ.get("CONNECTION") or os.environ.get( - "MESH_SERIAL", "/dev/ttyACM0" -) +CONNECTION = os.environ.get("CONNECTION", "/dev/ttyACM0") """Connection target opened to capture Meshtastic traffic.""" OUT = os.environ.get("MESH_DUMP_FILE", "meshtastic-dump.ndjson") diff --git a/tests/test_config_unit.py b/tests/test_config_unit.py index d2a0d64..4ea9afc 100644 --- a/tests/test_config_unit.py +++ b/tests/test_config_unit.py @@ -102,39 +102,27 @@ class TestResolveInstanceDomain: def test_returns_instance_domain_when_set(self, monkeypatch): """Uses INSTANCE_DOMAIN when set.""" monkeypatch.setenv("INSTANCE_DOMAIN", "mesh.example.com") - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) result = config._resolve_instance_domain() assert result == "https://mesh.example.com" def test_adds_https_when_no_scheme(self, monkeypatch): """Adds https:// prefix when no scheme is present.""" monkeypatch.setenv("INSTANCE_DOMAIN", "example.com") - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) assert config._resolve_instance_domain() == "https://example.com" def test_preserves_existing_scheme(self, monkeypatch): """Leaves existing http:// scheme intact.""" monkeypatch.setenv("INSTANCE_DOMAIN", "http://example.com") - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) assert config._resolve_instance_domain() == "http://example.com" def test_strips_trailing_slash(self, monkeypatch): """Strips trailing slash from instance domain.""" monkeypatch.setenv("INSTANCE_DOMAIN", "https://example.com/") - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) assert config._resolve_instance_domain() == "https://example.com" - def test_falls_back_to_legacy_env(self, monkeypatch): - """Falls back to POTATOMESH_INSTANCE when INSTANCE_DOMAIN is absent.""" + def test_returns_empty_when_not_set(self, monkeypatch): + """Returns empty string when INSTANCE_DOMAIN is unset.""" monkeypatch.delenv("INSTANCE_DOMAIN", raising=False) - monkeypatch.setenv("POTATOMESH_INSTANCE", "legacy.example.com") - result = config._resolve_instance_domain() - assert result == "https://legacy.example.com" - - def test_returns_empty_when_neither_set(self, monkeypatch): - """Returns empty string when neither env var is set.""" - monkeypatch.delenv("INSTANCE_DOMAIN", raising=False) - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) assert config._resolve_instance_domain() == "" @@ -221,52 +209,3 @@ class TestProtocolValidation: # Restore to valid value so subsequent tests work monkeypatch.setenv("PROTOCOL", "meshtastic") importlib.reload(config) - - def test_protocol_env_var_takes_priority_over_provider(self, monkeypatch): - """PROTOCOL env var must take precedence over legacy PROVIDER.""" - import importlib - - monkeypatch.setenv("PROTOCOL", "meshcore") - monkeypatch.setenv("PROVIDER", "meshtastic") - cfg = importlib.reload(config) - assert cfg.PROTOCOL == "meshcore" - assert cfg.PROVIDER == "meshcore" # alias stays in sync - # Restore - monkeypatch.delenv("PROTOCOL") - monkeypatch.delenv("PROVIDER") - importlib.reload(config) - - def test_provider_env_var_fallback(self, monkeypatch): - """Legacy PROVIDER env var must still be accepted when PROTOCOL is absent.""" - import importlib - - monkeypatch.delenv("PROTOCOL", raising=False) - monkeypatch.setenv("PROVIDER", "meshcore") - cfg = importlib.reload(config) - assert cfg.PROTOCOL == "meshcore" - assert cfg.PROVIDER == "meshcore" - # Restore - monkeypatch.delenv("PROVIDER") - importlib.reload(config) - - -# --------------------------------------------------------------------------- -# _ConfigModule proxy -# --------------------------------------------------------------------------- - - -class TestConfigModuleProxy: - """Tests for the :class:`config._ConfigModule` proxy behaviour.""" - - def test_connection_and_port_stay_in_sync(self): - """Setting CONNECTION also updates PORT and vice versa.""" - original_connection = config.CONNECTION - original_port = config.PORT - try: - config.CONNECTION = "tcp://testhost" - assert config.PORT == "tcp://testhost" - config.PORT = "serial:/dev/ttyUSB0" - assert config.CONNECTION == "serial:/dev/ttyUSB0" - finally: - config.CONNECTION = original_connection - config.PORT = original_port diff --git a/tests/test_daemon_unit.py b/tests/test_daemon_unit.py index b9adc46..1bb800d 100644 --- a/tests/test_daemon_unit.py +++ b/tests/test_daemon_unit.py @@ -891,13 +891,12 @@ def _reload_config() -> types.ModuleType: @pytest.fixture() -def reset_provider_config(): - """Reload config after the test so PROTOCOL/PROVIDER changes don't leak across tests.""" +def reset_protocol_config(): + """Reload config after the test so PROTOCOL changes don't leak across tests.""" yield import os os.environ.pop("PROTOCOL", None) - os.environ.pop("PROVIDER", None) _reload_config() @@ -908,28 +907,17 @@ def reset_provider_config(): ("meshcore", "meshcore"), ], ) -def test_config_protocol_env(monkeypatch, reset_provider_config, env_value, expected): +def test_config_protocol_env(monkeypatch, reset_protocol_config, env_value, expected): """PROTOCOL env var selects the protocol; absent defaults to 'meshtastic'.""" if env_value is None: monkeypatch.delenv("PROTOCOL", raising=False) - monkeypatch.delenv("PROVIDER", raising=False) else: monkeypatch.setenv("PROTOCOL", env_value) cfg = _reload_config() assert cfg.PROTOCOL == expected - assert cfg.PROVIDER == expected # deprecated alias stays in sync -def test_config_provider_env_fallback(monkeypatch, reset_provider_config): - """Legacy PROVIDER env var must still work when PROTOCOL is absent.""" - monkeypatch.delenv("PROTOCOL", raising=False) - monkeypatch.setenv("PROVIDER", "meshcore") - cfg = _reload_config() - assert cfg.PROTOCOL == "meshcore" - assert cfg.PROVIDER == "meshcore" - - -def test_config_protocol_unknown_raises(monkeypatch, reset_provider_config): +def test_config_protocol_unknown_raises(monkeypatch, reset_protocol_config): """An unrecognised PROTOCOL value must raise ValueError at import time.""" monkeypatch.setenv("PROTOCOL", "reticulum") with pytest.raises(ValueError, match="PROTOCOL"): diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 66cde4b..811658a 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -41,16 +41,6 @@ def reset_state(monkeypatch): importlib.reload(config) -def test_config_module_port_aliases(monkeypatch): - """Ensure the config module keeps CONNECTION and PORT in sync.""" - - reloaded = importlib.reload(config) - monkeypatch.setattr(reloaded, "CONNECTION", "dev-tty", raising=False) - reloaded.PORT = "new-port" - assert reloaded.CONNECTION == "new-port" - assert reloaded.PORT == "new-port" - - def test_queue_stringification_and_ordering(): """Exercise queue payload formatting and priority ordering.""" diff --git a/tests/test_mesh.py b/tests/test_mesh.py index eec0433..83bc087 100644 --- a/tests/test_mesh.py +++ b/tests/test_mesh.py @@ -228,10 +228,9 @@ def mesh_module(monkeypatch): def test_instance_domain_prefers_primary_env(mesh_module, monkeypatch): - """Ensure the ingestor prefers ``INSTANCE_DOMAIN`` over the legacy variable.""" + """Ensure the ingestor reads ``INSTANCE_DOMAIN``.""" monkeypatch.setenv("INSTANCE_DOMAIN", "https://new.example") - monkeypatch.setenv("POTATOMESH_INSTANCE", "https://legacy.example") try: refreshed_instance = mesh_module.config._resolve_instance_domain() @@ -242,26 +241,6 @@ def test_instance_domain_prefers_primary_env(mesh_module, monkeypatch): assert mesh_module.INSTANCE == "https://new.example" finally: monkeypatch.delenv("INSTANCE_DOMAIN", raising=False) - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) - mesh_module.config.INSTANCE = mesh_module.config._resolve_instance_domain() - mesh_module.INSTANCE = mesh_module.config.INSTANCE - - -def test_instance_domain_falls_back_to_legacy(mesh_module, monkeypatch): - """Verify ``POTATOMESH_INSTANCE`` is used when ``INSTANCE_DOMAIN`` is unset.""" - - monkeypatch.delenv("INSTANCE_DOMAIN", raising=False) - monkeypatch.setenv("POTATOMESH_INSTANCE", "https://legacy-only.example") - - try: - refreshed_instance = mesh_module.config._resolve_instance_domain() - mesh_module.config.INSTANCE = refreshed_instance - mesh_module.INSTANCE = refreshed_instance - - assert refreshed_instance == "https://legacy-only.example" - assert mesh_module.INSTANCE == "https://legacy-only.example" - finally: - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) mesh_module.config.INSTANCE = mesh_module.config._resolve_instance_domain() mesh_module.INSTANCE = mesh_module.config.INSTANCE @@ -270,7 +249,6 @@ def test_instance_domain_infers_scheme_for_hostnames(mesh_module, monkeypatch): """Ensure bare hostnames are promoted to HTTPS URLs for ingestion.""" monkeypatch.setenv("INSTANCE_DOMAIN", "mesh.example.org") - monkeypatch.delenv("POTATOMESH_INSTANCE", raising=False) try: refreshed_instance = mesh_module.config._resolve_instance_domain() @@ -1637,7 +1615,7 @@ def test_main_retries_interface_creation(mesh_module, monkeypatch): raise RuntimeError("boom") return iface, port - monkeypatch.setattr(mesh, "PORT", "/dev/ttyTEST") + monkeypatch.setattr(mesh, "CONNECTION", "/dev/ttyTEST") monkeypatch.setattr(mesh, "_create_serial_interface", fake_create) monkeypatch.setattr(mesh.threading, "Event", DummyEvent) monkeypatch.setattr(mesh.signal, "signal", lambda *_, **__: None) @@ -1709,7 +1687,7 @@ def test_main_reconnects_when_connection_event_clears(mesh_module, monkeypatch): self._flag = True return True - monkeypatch.setattr(mesh, "PORT", "/dev/ttyTEST") + monkeypatch.setattr(mesh, "CONNECTION", "/dev/ttyTEST") monkeypatch.setattr(mesh, "_create_serial_interface", fake_create) monkeypatch.setattr(mesh.threading, "Event", DummyStopEvent) monkeypatch.setattr(mesh.signal, "signal", lambda *_, **__: None) @@ -1773,7 +1751,7 @@ def test_main_recreates_interface_after_snapshot_error(mesh_module, monkeypatch) def record_upsert(node_id, node): upsert_calls.append(node_id) - monkeypatch.setattr(mesh, "PORT", "/dev/ttyTEST") + monkeypatch.setattr(mesh, "CONNECTION", "/dev/ttyTEST") monkeypatch.setattr(mesh, "_create_serial_interface", fake_create) monkeypatch.setattr(mesh, "upsert_node", record_upsert) monkeypatch.setattr(mesh.threading, "Event", DummyEvent) @@ -1795,7 +1773,7 @@ def test_main_exits_when_defaults_unavailable(mesh_module, monkeypatch): def fail_default(): raise mesh.NoAvailableMeshInterface("no interface available") - monkeypatch.setattr(mesh, "PORT", None) + monkeypatch.setattr(mesh, "CONNECTION", None) monkeypatch.setattr(mesh, "_create_default_interface", fail_default) monkeypatch.setattr(mesh.signal, "signal", lambda *_, **__: None) @@ -3203,7 +3181,7 @@ def test_queue_ingestor_heartbeat_enqueues_and_throttles(mesh_module, monkeypatc def test_queue_ingestor_heartbeat_protocol_meshcore(mesh_module, monkeypatch): - """Heartbeat payload must carry the configured PROVIDER as its protocol.""" + """Heartbeat payload must carry the configured PROTOCOL as its protocol.""" mesh = mesh_module captured = [] diff --git a/web/lib/potato_mesh/config.rb b/web/lib/potato_mesh/config.rb index af3ec56..ed8070d 100644 --- a/web/lib/potato_mesh/config.rb +++ b/web/lib/potato_mesh/config.rb @@ -187,7 +187,7 @@ module PotatoMesh # # @return [String] semantic version identifier. def version_fallback - "0.5.12" + "0.6.0" end # Default refresh interval for frontend polling routines. diff --git a/web/package-lock.json b/web/package-lock.json index 2fbfba0..a30c77c 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "potato-mesh", - "version": "0.5.12", + "version": "0.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "potato-mesh", - "version": "0.5.12", + "version": "0.6.0", "devDependencies": { "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", diff --git a/web/package.json b/web/package.json index b000bfe..546c158 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "potato-mesh", - "version": "0.5.12", + "version": "0.6.0", "type": "module", "private": true, "scripts": {