mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-27 02:45:24 +08:00
fix(plugin): allow unsigned Cloud plugins on dedicated workers
This commit is contained in:
@@ -29,6 +29,7 @@ pytestmark = pytest.mark.integration
|
||||
('deployment', 'archive_kind', 'administrator_force', 'expected_profile'),
|
||||
[
|
||||
('cloud', 'signed_shared', False, 'shared-runtime-v1'),
|
||||
('cloud', 'legacy', False, 'dedicated'),
|
||||
('oss', 'signed_shared', False, 'shared-runtime-v1'),
|
||||
('oss', 'legacy', False, 'dedicated'),
|
||||
('oss', 'forged_shared', True, 'dedicated'),
|
||||
@@ -75,7 +76,7 @@ async def test_install_plugin_admits_archive_before_persistence_and_applies_sele
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('archive_kind', ['legacy', 'invalid_shared'])
|
||||
@pytest.mark.parametrize('archive_kind', ['invalid_shared'])
|
||||
async def test_cloud_rejects_untrusted_archive_before_storage_persistence_or_runtime_apply(archive_kind: str) -> None:
|
||||
package, trusted_public_keys = _archive(archive_kind)
|
||||
connector, _execution_context, _binding = _connector('cloud', trusted_public_keys)
|
||||
@@ -180,26 +181,20 @@ async def test_marketplace_version_selection_keeps_certificate_gate_and_single_a
|
||||
if requested_version is not None:
|
||||
info['plugin_version'] = requested_version
|
||||
task_context = TaskContext.new()
|
||||
if archive_kind == 'legacy':
|
||||
with pytest.raises(ValueError, match='CERTIFIED_PLUGIN_CLOUD_CERTIFICATE_REQUIRED'):
|
||||
await connector.install_plugin(PluginInstallSource.MARKETPLACE, info, task_context)
|
||||
connector._store_artifact_package.assert_not_awaited()
|
||||
connector._persist_installation_package.assert_not_awaited()
|
||||
connector.handler.apply_plugin_installation.assert_not_awaited()
|
||||
connector._refresh_runner_registry.assert_not_awaited()
|
||||
else:
|
||||
await connector.install_plugin(PluginInstallSource.MARKETPLACE, info, task_context)
|
||||
persisted_info = connector._persist_installation_package.await_args.kwargs['install_info']
|
||||
assert persisted_info['plugin_version'] == '1.0.0'
|
||||
assert persisted_info['_certification']['runtime_profile'] == 'shared-runtime-v1'
|
||||
connector.handler.apply_plugin_installation.assert_awaited_once_with(
|
||||
binding,
|
||||
artifact_package=package,
|
||||
enabled=True,
|
||||
execution_mode=PluginExecutionMode.SHARED_CERTIFIED,
|
||||
)
|
||||
connector._refresh_runner_registry.assert_awaited_once()
|
||||
assert task_context.metadata['progress_percent'] == 100
|
||||
await connector.install_plugin(PluginInstallSource.MARKETPLACE, info, task_context)
|
||||
persisted_info = connector._persist_installation_package.await_args.kwargs['install_info']
|
||||
assert persisted_info['plugin_version'] == '1.0.0'
|
||||
assert persisted_info['_certification']['runtime_profile'] == (
|
||||
'shared-runtime-v1' if archive_kind == 'signed_shared' else 'dedicated'
|
||||
)
|
||||
connector.handler.apply_plugin_installation.assert_awaited_once_with(
|
||||
binding,
|
||||
artifact_package=package,
|
||||
enabled=True,
|
||||
execution_mode=(PluginExecutionMode.SHARED_CERTIFIED if archive_kind == 'signed_shared' else PluginExecutionMode.DEDICATED),
|
||||
)
|
||||
connector._refresh_runner_registry.assert_awaited_once()
|
||||
assert task_context.metadata['progress_percent'] == 100
|
||||
if requested_version is not None:
|
||||
# Confirmed migrations must fetch the reviewed release, never latest/MCP/skill.
|
||||
assert len(requests) == 1
|
||||
|
||||
@@ -13,7 +13,8 @@ from langbot_plugin.entities.io.context import PluginExecutionMode
|
||||
('deployment', 'certificate', 'certificate_id', 'force', 'expected_disposition', 'expected_code'),
|
||||
[
|
||||
('cloud', ('valid', 'shared-runtime-v1'), 'issuer', False, 'shared_eligible', 'CERTIFIED_PLUGIN_SHARED_ELIGIBLE'),
|
||||
('cloud', ('absent', None), None, False, 'rejected', 'CERTIFIED_PLUGIN_CLOUD_CERTIFICATE_REQUIRED'),
|
||||
('cloud', ('absent', None), None, False, 'dedicated_allowed', 'CERTIFIED_PLUGIN_UNSIGNED_DEDICATED'),
|
||||
('cloud', ('absent', None), None, True, 'dedicated_allowed', 'CERTIFIED_PLUGIN_UNSIGNED_DEDICATED'),
|
||||
('cloud', ('malformed', None), None, False, 'rejected', 'CERTIFIED_PLUGIN_CLOUD_CERTIFICATE_INVALID'),
|
||||
(
|
||||
'cloud',
|
||||
@@ -134,6 +135,27 @@ def test_legacy_shared_certificate_without_stateless_contract_is_not_shared() ->
|
||||
assert decision.disposition is AdmissionDisposition.REJECTED
|
||||
|
||||
|
||||
def test_oss_does_not_treat_valid_nonshared_signature_as_dedicated_certification() -> None:
|
||||
from langbot.pkg.plugin.certification import (
|
||||
AdmissionDisposition, CertificateFacts, CertificateVerification,
|
||||
PluginCertificationFacts, decide_plugin_admission,
|
||||
)
|
||||
|
||||
decision = decide_plugin_admission(
|
||||
deployment='oss',
|
||||
facts=PluginCertificationFacts(
|
||||
installation_uuid='00000000-0000-4000-8000-000000000001',
|
||||
artifact_digest='a' * 64,
|
||||
certificate=CertificateFacts(
|
||||
verification=CertificateVerification.VALID,
|
||||
runtime_profile=None,
|
||||
certificate_id='issuer',
|
||||
),
|
||||
),
|
||||
)
|
||||
assert decision.disposition is AdmissionDisposition.ADMINISTRATOR_FORCE_REQUIRED
|
||||
|
||||
|
||||
def test_archive_inspection_preserves_legacy_tuple_and_exposes_certificate_facts() -> None:
|
||||
from langbot.pkg.plugin.archive import (
|
||||
ArchiveCertificateState,
|
||||
|
||||
Reference in New Issue
Block a user