mirror of
https://github.com/langgenius/dify.git
synced 2026-11-12 06:11:12 +08:00
Add revision-scoped stable saved-model inventory and source plugin admission. Preserve independent and BYOK owners, frozen contracts, actual schema RPC boundaries and non-secret source protocol facts.
145 lines
5.7 KiB
Python
145 lines
5.7 KiB
Python
"""Admitted plugin binding mutations, before any daemon installation side effect.
|
|
|
|
Download, signature checks and cache invalidation belong to the gateway. All
|
|
manual, import and asynchronous callers share this application entry point.
|
|
"""
|
|
|
|
from collections.abc import Sequence
|
|
from dataclasses import dataclass
|
|
from typing import Literal, Protocol
|
|
|
|
type PluginInstallationOperation = Literal["package", "marketplace", "github", "upgrade_marketplace", "upgrade_github"]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class AdmittedPluginInstallationCaller:
|
|
"""Workspace scope already admitted by transport or an internal task owner."""
|
|
|
|
tenant_id: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class PluginInstallationResult:
|
|
all_installed: bool
|
|
task_id: str
|
|
# None means the daemon has not returned the optional task snapshot.
|
|
task: dict[str, object] | None
|
|
|
|
|
|
class PluginInstallationAdmission(Protocol):
|
|
def assert_allowed(self, caller: AdmittedPluginInstallationCaller, candidate_uids: Sequence[str]) -> None:
|
|
"""Reject incompatible replacements before download/upload/install/upgrade.
|
|
|
|
This is an admission check, not an atomic database/daemon transaction.
|
|
Implementations must fail closed on uncertain active route facts.
|
|
"""
|
|
...
|
|
|
|
|
|
class PluginBindingMutations(Protocol):
|
|
def assert_available(
|
|
self,
|
|
operation: PluginInstallationOperation,
|
|
original_uid: str | None,
|
|
candidate_uid: str | None,
|
|
) -> None:
|
|
"""Preserve existing non-mutating source-policy admission before route reads.
|
|
|
|
None original/candidate identifies a non-upgrade or package batch.
|
|
No download, daemon call, cache invalidation or credential access.
|
|
"""
|
|
...
|
|
|
|
def install_from_local_pkg(
|
|
self, tenant_id: str, plugin_unique_identifiers: Sequence[str]
|
|
) -> PluginInstallationResult: ...
|
|
|
|
def install_from_marketplace_pkg(
|
|
self, tenant_id: str, plugin_unique_identifiers: Sequence[str]
|
|
) -> PluginInstallationResult: ...
|
|
|
|
def install_from_github(
|
|
self, tenant_id: str, plugin_unique_identifier: str, repo: str, version: str, package: str
|
|
) -> PluginInstallationResult: ...
|
|
|
|
def upgrade_plugin_with_marketplace(
|
|
self, tenant_id: str, original_plugin_unique_identifier: str, new_plugin_unique_identifier: str
|
|
) -> PluginInstallationResult: ...
|
|
|
|
def upgrade_plugin_with_github(
|
|
self,
|
|
tenant_id: str,
|
|
original_plugin_unique_identifier: str,
|
|
new_plugin_unique_identifier: str,
|
|
repo: str,
|
|
version: str,
|
|
package: str,
|
|
) -> PluginInstallationResult: ...
|
|
|
|
|
|
class PluginInstallationService:
|
|
def __init__(self, *, admission: PluginInstallationAdmission, mutations: PluginBindingMutations) -> None:
|
|
self._admission = admission
|
|
self._mutations = mutations
|
|
|
|
def assert_installable(self, caller: AdmittedPluginInstallationCaller, candidate_uids: Sequence[str]) -> None:
|
|
"""Admit legacy bulk owners that retain their stricter signature mechanics."""
|
|
self._admission.assert_allowed(caller, candidate_uids)
|
|
|
|
def install_from_local_pkg(
|
|
self, caller: AdmittedPluginInstallationCaller, plugin_unique_identifiers: Sequence[str]
|
|
) -> PluginInstallationResult:
|
|
self._mutations.assert_available("package", None, None)
|
|
self._admission.assert_allowed(caller, plugin_unique_identifiers)
|
|
return self._mutations.install_from_local_pkg(caller.tenant_id, plugin_unique_identifiers)
|
|
|
|
def install_from_marketplace_pkg(
|
|
self, caller: AdmittedPluginInstallationCaller, plugin_unique_identifiers: Sequence[str]
|
|
) -> PluginInstallationResult:
|
|
self._mutations.assert_available("marketplace", None, None)
|
|
self._admission.assert_allowed(caller, plugin_unique_identifiers)
|
|
return self._mutations.install_from_marketplace_pkg(caller.tenant_id, plugin_unique_identifiers)
|
|
|
|
def install_from_github(
|
|
self,
|
|
caller: AdmittedPluginInstallationCaller,
|
|
plugin_unique_identifier: str,
|
|
repo: str,
|
|
version: str,
|
|
package: str,
|
|
) -> PluginInstallationResult:
|
|
self._mutations.assert_available("github", None, plugin_unique_identifier)
|
|
self._admission.assert_allowed(caller, (plugin_unique_identifier,))
|
|
return self._mutations.install_from_github(caller.tenant_id, plugin_unique_identifier, repo, version, package)
|
|
|
|
def upgrade_plugin_with_marketplace(
|
|
self,
|
|
caller: AdmittedPluginInstallationCaller,
|
|
original_plugin_unique_identifier: str,
|
|
new_plugin_unique_identifier: str,
|
|
) -> PluginInstallationResult:
|
|
self._mutations.assert_available(
|
|
"upgrade_marketplace", original_plugin_unique_identifier, new_plugin_unique_identifier
|
|
)
|
|
self._admission.assert_allowed(caller, (new_plugin_unique_identifier,))
|
|
return self._mutations.upgrade_plugin_with_marketplace(
|
|
caller.tenant_id, original_plugin_unique_identifier, new_plugin_unique_identifier
|
|
)
|
|
|
|
def upgrade_plugin_with_github(
|
|
self,
|
|
caller: AdmittedPluginInstallationCaller,
|
|
original_plugin_unique_identifier: str,
|
|
new_plugin_unique_identifier: str,
|
|
repo: str,
|
|
version: str,
|
|
package: str,
|
|
) -> PluginInstallationResult:
|
|
self._mutations.assert_available(
|
|
"upgrade_github", original_plugin_unique_identifier, new_plugin_unique_identifier
|
|
)
|
|
self._admission.assert_allowed(caller, (new_plugin_unique_identifier,))
|
|
return self._mutations.upgrade_plugin_with_github(
|
|
caller.tenant_id, original_plugin_unique_identifier, new_plugin_unique_identifier, repo, version, package
|
|
)
|