From af173297fcf7f9aeb7412ffc47b44e273b450fe8 Mon Sep 17 00:00:00 2001 From: JosephTian876 Date: Sun, 2 Aug 2026 23:30:28 +0800 Subject: [PATCH 1/2] fix: warn when an explicitly configured WebUI dist is stale resolve_dashboard_dist() returns an explicitly configured --webui-dir immediately, without checking the version it declares. Every other branch in the same function verifies compatibility and warns on a mismatch, so this is the one way to end up serving assets that do not match the running core with no diagnostic at all. That is the case a packaged distribution hits: when the launcher updates the backend but keeps its bundled WebUI directory, the dashboard silently stays on the previous release. Features added by the new core are simply missing from the UI and nothing explains why. Behaviour is unchanged -- the directory is still served, since refusing to serve it would be worse than serving an old one. It is just no longer silent. --- astrbot/core/dashboard_assets.py | 13 +++- tests/unit/test_dashboard_dist_resolution.py | 70 ++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_dashboard_dist_resolution.py diff --git a/astrbot/core/dashboard_assets.py b/astrbot/core/dashboard_assets.py index e94e80631b..a97da229a8 100644 --- a/astrbot/core/dashboard_assets.py +++ b/astrbot/core/dashboard_assets.py @@ -142,7 +142,18 @@ def resolve_dashboard_dist(webui_dir: str | Path | None = None) -> Path | None: None when an existing managed dist is incomplete. """ if webui_dir and Path(webui_dir).exists(): - return Path(webui_dir).absolute() + explicit_dist = Path(webui_dir).absolute() + if not _is_dist_compatible(explicit_dist, VERSION): + logger.warning( + "Serving the explicitly configured WebUI directory even though it " + "does not declare a version matching core: %s, expected v%s (%s). " + "Some dashboard features may not work until matching assets are " + "available.", + _read_dashboard_version(explicit_dist) or "unknown", + VERSION, + explicit_dist, + ) + return explicit_dist user_dist = Path(get_astrbot_data_path()) / "dist" bundled_dist = _get_bundled_dist_path() diff --git a/tests/unit/test_dashboard_dist_resolution.py b/tests/unit/test_dashboard_dist_resolution.py new file mode 100644 index 0000000000..52096d8ed6 --- /dev/null +++ b/tests/unit/test_dashboard_dist_resolution.py @@ -0,0 +1,70 @@ +"""Tests for resolve_dashboard_dist() when an explicit WebUI directory is used.""" + +import logging + +import pytest + +from astrbot.core.config.default import VERSION +from astrbot.core.dashboard_assets import resolve_dashboard_dist + +WARNING_FRAGMENT = "does not declare a version matching core" + + +def _make_dist(root, version: str | None) -> str: + assets = root / "assets" + assets.mkdir(parents=True) + (root / "index.html").write_text("", encoding="utf-8") + if version is not None: + (assets / "version").write_text(version, encoding="utf-8") + return str(root) + + +class TestExplicitWebuiDir: + def test_matching_version_is_served_quietly(self, tmp_path, caplog): + """The happy path must not add startup noise.""" + dist = _make_dist(tmp_path / "webui", f"v{VERSION}") + + with caplog.at_level(logging.WARNING): + resolved = resolve_dashboard_dist(dist) + + assert resolved is not None + assert str(resolved) == str(tmp_path / "webui") + assert WARNING_FRAGMENT not in caplog.text + + def test_mismatched_version_warns_but_is_still_served(self, tmp_path, caplog): + """A stale packaged WebUI must not be swapped in silently.""" + dist = _make_dist(tmp_path / "webui", "v0.0.1") + + with caplog.at_level(logging.WARNING): + resolved = resolve_dashboard_dist(dist) + + assert resolved is not None # behaviour unchanged: still served + assert WARNING_FRAGMENT in caplog.text + assert "v0.0.1" in caplog.text + assert VERSION in caplog.text + + def test_missing_version_marker_warns_as_unknown(self, tmp_path, caplog): + """Assets without a version marker cannot be verified, so say so.""" + dist = _make_dist(tmp_path / "webui", None) + + with caplog.at_level(logging.WARNING): + resolved = resolve_dashboard_dist(dist) + + assert resolved is not None + assert WARNING_FRAGMENT in caplog.text + assert "unknown" in caplog.text + + def test_nonexistent_dir_falls_through(self, tmp_path, caplog): + """A path that does not exist must not be reported as a stale dist.""" + with caplog.at_level(logging.WARNING): + resolve_dashboard_dist(str(tmp_path / "does-not-exist")) + + assert WARNING_FRAGMENT not in caplog.text + + @pytest.mark.parametrize("empty", ["", None]) + def test_no_explicit_dir_falls_through(self, empty, caplog): + """Without --webui-dir the managed/bundled resolution path is used.""" + with caplog.at_level(logging.WARNING): + resolve_dashboard_dist(empty) + + assert WARNING_FRAGMENT not in caplog.text From 1959b86f2189c45ff1df661b5e66ba533bc4b499 Mon Sep 17 00:00:00 2001 From: JosephTian876 Date: Sun, 2 Aug 2026 23:39:25 +0800 Subject: [PATCH 2/2] refactor: tidy the explicit WebUI dist resolution Build the Path once instead of twice, and hold the version read for the warning in a local so the log call only carries values. --- astrbot/core/dashboard_assets.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/astrbot/core/dashboard_assets.py b/astrbot/core/dashboard_assets.py index a97da229a8..36163a2318 100644 --- a/astrbot/core/dashboard_assets.py +++ b/astrbot/core/dashboard_assets.py @@ -141,15 +141,16 @@ def resolve_dashboard_dist(webui_dir: str | Path | None = None) -> Path | None: Explicit, managed, bundled, or stale fallback dist in priority order; None when an existing managed dist is incomplete. """ - if webui_dir and Path(webui_dir).exists(): - explicit_dist = Path(webui_dir).absolute() + explicit_dist = Path(webui_dir).absolute() if webui_dir else None + if explicit_dist is not None and explicit_dist.exists(): if not _is_dist_compatible(explicit_dist, VERSION): + explicit_version = _read_dashboard_version(explicit_dist) or "unknown" logger.warning( "Serving the explicitly configured WebUI directory even though it " "does not declare a version matching core: %s, expected v%s (%s). " "Some dashboard features may not work until matching assets are " "available.", - _read_dashboard_version(explicit_dist) or "unknown", + explicit_version, VERSION, explicit_dist, )