Skip to content

fix: Protect desktop plugin installs with core lock#7872

Merged
zouyonghe merged 1 commit intomasterfrom
codex/desktop-core-lock-plugin-deps
Apr 28, 2026
Merged

fix: Protect desktop plugin installs with core lock#7872
zouyonghe merged 1 commit intomasterfrom
codex/desktop-core-lock-plugin-deps

Conversation

@zouyonghe
Copy link
Copy Markdown
Member

@zouyonghe zouyonghe commented Apr 28, 2026

Summary

Adds packaged desktop support for consuming a runtime core dependency lock exposed by AstrBot Desktop. The pip installer now merges locked desktop runtime packages into its constraints file and skips locked top-level modules during post-install dependency preference. This prevents plugin installs from replacing already-loaded backend runtime packages such as OpenAI, Pydantic, FastAPI, NumPy, or platform-native bridge modules.

Why

Desktop plugin installs currently target data/site-packages and then try to prefer those modules in the live backend process. Heavy plugins can install alternate versions of packages already used by the core runtime, which can corrupt module identity and break streaming/model calls until restart. The lock turns that into either a compatible install using the bundled versions or an explicit dependency conflict.

Tests

  • uv run pytest tests/test_pip_installer.py -q
  • uv run ruff check astrbot/core/utils/desktop_core_lock.py astrbot/core/utils/core_constraints.py astrbot/core/utils/pip_installer.py tests/test_pip_installer.py
  • uv run ruff format --check astrbot/core/utils/desktop_core_lock.py astrbot/core/utils/core_constraints.py astrbot/core/utils/pip_installer.py tests/test_pip_installer.py

Summary by Sourcery

Integrate desktop runtime core lock data into plugin installation to avoid overriding bundled desktop dependencies.

Enhancements:

  • Add a desktop core lock utility for reading locked distributions and modules from a JSON lock file in packaged desktop runtimes.
  • Merge desktop core lock constraints into the core constraints file used by the pip installer so locked runtime packages are always pinned during installs.
  • Update plugin dependency preference logic to skip modules covered by the desktop core lock when preferring plugin-installed packages.

Tests:

  • Extend pip installer tests to cover use of desktop core lock constraints and ensure locked modules are excluded from plugin dependency preference.

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Apr 28, 2026
@zouyonghe zouyonghe changed the title [codex] Protect desktop plugin installs with core lock fix: Protect desktop plugin installs with core lock Apr 28, 2026
@dosubot dosubot Bot added area:core The bug / feature is about astrbot's core, backend feature:plugin The bug / feature is about AstrBot plugin system. labels Apr 28, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


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.

Copy link
Copy Markdown
Contributor

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

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 introduces a mechanism to manage desktop-specific core dependency locks by adding desktop_core_lock.py, which parses a JSON lock file defined by an environment variable. These locked constraints are integrated into the core constraint provider, and the pip installer is updated to exclude these modules from plugin dependency preference logic. Feedback suggests refactoring the distribution name canonicalization to use an existing utility to avoid duplication and ensuring that requirement pins use canonicalized names to guarantee correct deduplication when merging constraints.

Comment on lines +4 to +16
import re
from functools import lru_cache
from typing import Any

from astrbot.core.utils.runtime_env import is_packaged_desktop_runtime

logger = logging.getLogger("astrbot")

DESKTOP_CORE_LOCK_PATH_ENV = "ASTRBOT_DESKTOP_CORE_LOCK_PATH"


def _canonicalize_distribution_name(name: str) -> str:
return re.sub(r"[-_.]+", "-", name).strip("-").lower()
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

The function _canonicalize_distribution_name is identical to canonicalize_distribution_name in requirements_utils.py. To avoid code duplication and maintain consistency, it is recommended to import the existing utility. This also allows for the removal of the import re statement as it is not used elsewhere in this module.

from functools import lru_cache
from typing import Any

from astrbot.core.utils.runtime_env import is_packaged_desktop_runtime
from astrbot.core.utils.requirements_utils import (
    canonicalize_distribution_name as _canonicalize_distribution_name,
)

logger = logging.getLogger("astrbot")

DESKTOP_CORE_LOCK_PATH_ENV = "ASTRBOT_DESKTOP_CORE_LOCK_PATH"
References
  1. When implementing similar functionality for different cases, refactor the logic into a shared helper function to avoid code duplication.

Comment on lines +82 to +85
pin = _safe_requirement_pin(name, version)
if not pin:
continue
constraints.setdefault(_canonicalize_distribution_name(name), pin)
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

In get_desktop_core_lock_constraints, the requirement pin should use the canonicalized distribution name. This ensures that when these constraints are merged with core constraints in core_constraints.py, the dict.fromkeys deduplication works correctly even if the lock file uses different casing or separators for the package name compared to the core metadata.

Suggested change
pin = _safe_requirement_pin(name, version)
if not pin:
continue
constraints.setdefault(_canonicalize_distribution_name(name), pin)
canonical_name = _canonicalize_distribution_name(name)
pin = _safe_requirement_pin(canonical_name, version)
if not pin:
continue
constraints.setdefault(canonical_name, pin)

@zouyonghe zouyonghe merged commit 2f33c34 into master Apr 28, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend feature:plugin The bug / feature is about AstrBot plugin system. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant