Skip to content

fix: validate WebUI dist before reuse#8785

Open
he-yufeng wants to merge 1 commit into
AstrBotDevs:masterfrom
he-yufeng:fix/validate-webui-dist
Open

fix: validate WebUI dist before reuse#8785
he-yufeng wants to merge 1 commit into
AstrBotDevs:masterfrom
he-yufeng:fix/validate-webui-dist

Conversation

@he-yufeng

@he-yufeng he-yufeng commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #8784.

Summary

  • check data/dist/index.html, data/dist/assets, and data/dist/assets/version before reusing the cached WebUI directory
  • redownload the WebUI when the local dist is only a partial directory
  • keep explicit webui_dir behavior unchanged

To verify

  • python -m py_compile main.py tests\test_main.py
  • python -m ruff check main.py tests\test_main.py
  • python -m ruff format --check main.py tests\test_main.py
  • python -m pytest tests\test_main.py -q -p no:cacheprovider
  • git diff --check

Summary by Sourcery

Ensure the WebUI cache is only reused when the local dist directory is complete and valid, otherwise trigger a fresh download.

Bug Fixes:

  • Validate the presence of key WebUI dist files before reusing a cached WebUI directory to avoid running with a partial or corrupted build.

Tests:

  • Extend dashboard file checks tests to cover incomplete dist directories and to assert correct behavior when required WebUI assets are present or missing.

@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. area:webui The bug / feature is about webui(dashboard) of astrbot. labels Jun 14, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tests/test_main.py" line_range="161-162" />
<code_context>
     """Tests that dashboard is not downloaded when it exists and version matches."""
     # Mock os.path.exists to return True
     monkeypatch.setattr(os.path, "exists", lambda x: True)
+    monkeypatch.setattr(os.path, "isfile", lambda x: True)
+    monkeypatch.setattr(os.path, "isdir", lambda x: True)

     # Mock get_dashboard_version to return the current version
</code_context>
<issue_to_address>
**suggestion (testing):** Avoid globally returning True for os.path.isfile/isdir in these tests to better reflect real filesystem state

In `test_check_dashboard_files_exists_and_version_match` and `test_check_dashboard_files_exists_but_version_mismatch`, `os.path.isfile`/`os.path.isdir` are patched to always return `True`, which can hide issues if more path checks are added later. Instead, either:

1. Build a minimal `dist` structure under `tmp_path` (as in `test_check_dashboard_files_uses_bundled_dist_when_data_dist_is_stale`) and avoid patching `isfile`/`isdir`, or
2. Patch them to return `True` only for the specific `data/dist/index.html`, `data/dist/assets`, and `data/dist/assets/version` paths, delegating to the real implementation otherwise.

This will keep the tests aligned with the actual filesystem checks and reduce false positives as the implementation evolves.

Suggested implementation:

```python
    orig_isfile = os.path.isfile

    def _test_isfile(path):
        path_str = os.fspath(path)
        if path_str.endswith(os.path.join("data", "dist", "index.html")):
            return True
        if path_str.endswith(os.path.join("data", "dist", "assets", "version")):
            return True
        return orig_isfile(path)

    monkeypatch.setattr(os.path, "isfile", _test_isfile)

```

```python
    orig_isdir = os.path.isdir

    def _test_isdir(path):
        path_str = os.fspath(path)
        if path_str.endswith(os.path.join("data", "dist", "assets")):
            return True
        return orig_isdir(path)

    monkeypatch.setattr(os.path, "isdir", _test_isdir)

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread tests/test_main.py
Comment on lines +161 to +162
monkeypatch.setattr(os.path, "isfile", lambda x: True)
monkeypatch.setattr(os.path, "isdir", lambda x: True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Avoid globally returning True for os.path.isfile/isdir in these tests to better reflect real filesystem state

In test_check_dashboard_files_exists_and_version_match and test_check_dashboard_files_exists_but_version_mismatch, os.path.isfile/os.path.isdir are patched to always return True, which can hide issues if more path checks are added later. Instead, either:

  1. Build a minimal dist structure under tmp_path (as in test_check_dashboard_files_uses_bundled_dist_when_data_dist_is_stale) and avoid patching isfile/isdir, or
  2. Patch them to return True only for the specific data/dist/index.html, data/dist/assets, and data/dist/assets/version paths, delegating to the real implementation otherwise.

This will keep the tests aligned with the actual filesystem checks and reduce false positives as the implementation evolves.

Suggested implementation:

    orig_isfile = os.path.isfile

    def _test_isfile(path):
        path_str = os.fspath(path)
        if path_str.endswith(os.path.join("data", "dist", "index.html")):
            return True
        if path_str.endswith(os.path.join("data", "dist", "assets", "version")):
            return True
        return orig_isfile(path)

    monkeypatch.setattr(os.path, "isfile", _test_isfile)
    orig_isdir = os.path.isdir

    def _test_isdir(path):
        path_str = os.fspath(path)
        if path_str.endswith(os.path.join("data", "dist", "assets")):
            return True
        return orig_isdir(path)

    monkeypatch.setattr(os.path, "isdir", _test_isdir)

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the WebUI directory check in main.py to ensure that the data/dist directory is complete (containing index.html, assets, and version) before using it, falling back to downloading a fresh copy if any files are missing. Corresponding tests in tests/test_main.py have been updated and a new test has been added. Feedback suggests cleaning up the incomplete data/dist path before downloading to prevent extraction conflicts, and restricting the global mocks of os.path.isfile and os.path.isdir in tests to target only the distribution paths to avoid side effects.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread main.py
Comment on lines +90 to 93
logger.warning(
"WebUI directory is incomplete: %s. Downloading a fresh copy.",
data_dist_path,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the WebUI directory is incomplete or corrupted, simply logging a warning and proceeding to download might lead to extraction conflicts (e.g., if data/dist is actually a file instead of a directory, or if there are leftover orphaned files from a previous failed installation). Cleaning up the incomplete path before downloading ensures a clean and reliable extraction state.

Suggested change
logger.warning(
"WebUI directory is incomplete: %s. Downloading a fresh copy.",
data_dist_path,
)
logger.warning(
"WebUI directory is incomplete: %s. Downloading a fresh copy.",
data_dist_path,
)
import shutil
if os.path.isdir(data_dist_path):
shutil.rmtree(data_dist_path, ignore_errors=True)
else:
try:
os.remove(data_dist_path)
except Exception:
pass

Comment thread tests/test_main.py
Comment on lines +161 to +162
monkeypatch.setattr(os.path, "isfile", lambda x: True)
monkeypatch.setattr(os.path, "isdir", lambda x: True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Globally mocking os.path.isfile and os.path.isdir to always return True can cause unexpected side effects in other parts of the test suite or standard library calls. It is safer to restrict the mock to return True only for paths related to the dashboard distribution.

Suggested change
monkeypatch.setattr(os.path, "isfile", lambda x: True)
monkeypatch.setattr(os.path, "isdir", lambda x: True)
monkeypatch.setattr(os.path, "isfile", lambda x: "dist" in str(x))
monkeypatch.setattr(os.path, "isdir", lambda x: "dist" in str(x))

Comment thread tests/test_main.py
Comment on lines +181 to +182
monkeypatch.setattr(os.path, "isfile", lambda x: True)
monkeypatch.setattr(os.path, "isdir", lambda x: True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Globally mocking os.path.isfile and os.path.isdir to always return True can cause unexpected side effects in other parts of the test suite or standard library calls. It is safer to restrict the mock to return True only for paths related to the dashboard distribution.

Suggested change
monkeypatch.setattr(os.path, "isfile", lambda x: True)
monkeypatch.setattr(os.path, "isdir", lambda x: True)
monkeypatch.setattr(os.path, "isfile", lambda x: "dist" in str(x))
monkeypatch.setattr(os.path, "isdir", lambda x: "dist" in str(x))

@Cyrene2026

Copy link
Copy Markdown

你好,依据你的pr,确实能够覆盖到index.html、assets/、assets/version缺失的三个问题,但是我想确认一下,是否存在以下情况:
dashboard/server.py 仍会在 webui_dir=None 时用 os.path.exists(user_dist)
重新选择 data/dist。若下载失败,是否仍可能 fallback 到损坏 dist 并显示 WebUI is ready

@he-yufeng

Copy link
Copy Markdown
Contributor Author

The failing Unit Tests job is hitting the same FastAPI 0.137 route-introspection compatibility issue that #8783 fixes:

  • test_v1_openapi_alias_websocket_routes_are_mounted
  • test_dashboard_config_aliases_are_registered_on_fastapi

This PR's local targeted checks are still clean (tests/test_main.py passed). I am keeping this branch limited to the WebUI dist validation change instead of copying the unrelated test-compat patch here; once #8783 lands, a rebase should clear this CI failure.

@zouyonghe zouyonghe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. The fix is scoped to rejecting incomplete cached directories before reuse, while preserving explicit behavior. Tests cover the partial-dist case and stale bundled-dist path. The current full pytest failure matches the unrelated FastAPI 0.137 route-test issue fixed by #8783.

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jun 15, 2026

@zouyonghe zouyonghe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. The fix is scoped to rejecting incomplete cached data/dist directories before reuse, while preserving explicit webui_dir behavior. Tests cover the partial-dist case and stale bundled-dist path. The current full pytest failure matches the unrelated FastAPI 0.137 route-test issue fixed by #8783.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:webui The bug / feature is about webui(dashboard) of astrbot. lgtm This PR has been approved by a maintainer size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] WebUI dist 缺失 index/assets 时启动阶段未校验,仍继续启动

3 participants