mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-08 20:30:59 +00:00
feat(cloud): harden multi-tenant runtime resources
This commit is contained in:
@@ -12,6 +12,7 @@ import zipfile
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -123,6 +124,17 @@ class TestExtractDepsMetadata:
|
||||
# Should find requirements.txt in subdirectory
|
||||
assert task_context.metadata['deps_total'] == 2
|
||||
|
||||
def test_archive_preview_rejects_extreme_compression_ratio(self):
|
||||
from langbot.pkg.plugin.connector import inspect_plugin_archive_metadata
|
||||
|
||||
zip_buffer = io.BytesIO()
|
||||
with zipfile.ZipFile(zip_buffer, 'w', compression=zipfile.ZIP_DEFLATED) as zf:
|
||||
zf.writestr('manifest.yaml', 'kind: Plugin\nmetadata: {}\n')
|
||||
zf.writestr('bomb.py', b'A' * (1024 * 1024))
|
||||
|
||||
with pytest.raises(ValueError, match='compression-ratio limit'):
|
||||
inspect_plugin_archive_metadata(zip_buffer.getvalue())
|
||||
|
||||
|
||||
class TestParsePluginId:
|
||||
"""Tests for _parse_plugin_id static method."""
|
||||
@@ -141,3 +153,13 @@ class TestParsePluginId:
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
PluginRuntimeConnector._parse_plugin_id('')
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_marketplace_response_reader_is_bounded():
|
||||
from langbot.pkg.plugin.connector import _read_httpx_response_limited
|
||||
|
||||
response = httpx.Response(200, content=b'oversized')
|
||||
|
||||
with pytest.raises(ValueError, match='exceeds'):
|
||||
await _read_httpx_response_limited(response, max_bytes=4)
|
||||
|
||||
@@ -136,6 +136,23 @@ async def test_shared_reconnect_replays_two_workspaces_and_removes_missing_proje
|
||||
assert set(connector._known_desired_states) == {setting_a.installation_uuid}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_projected_workspaces_do_not_retain_installation_sets():
|
||||
binding_a = execution_binding('workspace-a')
|
||||
binding_b = execution_binding('workspace-b')
|
||||
connector = shared_connector(
|
||||
[[binding_a, binding_b]],
|
||||
{'workspace-a': [], 'workspace-b': []},
|
||||
)
|
||||
connector.handler = runtime_handler()
|
||||
|
||||
await connector._prepare_connected_runtime()
|
||||
|
||||
assert connector._workspace_installations == {}
|
||||
assert connector._known_desired_states == {}
|
||||
connector.handler.reconcile_plugin_installations.assert_awaited_once_with(())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fresh_shared_runtime_cache_replays_persisted_local_package():
|
||||
package = b'local-lbpkg-bytes'
|
||||
|
||||
@@ -257,7 +257,7 @@ class TestSetBinaryStorage:
|
||||
)
|
||||
|
||||
assert response.code != 0
|
||||
assert '2048 > 1024 bytes' in response.message
|
||||
assert '1024-byte limit' in response.message
|
||||
app.persistence_mgr.execute_async.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -312,21 +312,25 @@ class TestSetBinaryStorage:
|
||||
)
|
||||
|
||||
assert response.code != 0
|
||||
assert '10485761 > 10485760 bytes' in response.message
|
||||
assert '10485760' in response.message
|
||||
app.persistence_mgr.execute_async.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_negative_limit_disables_size_check(self, app):
|
||||
"""Negative max_value_bytes allows values larger than the normal default."""
|
||||
async def test_negative_limit_falls_back_to_bounded_default(self, app, monkeypatch):
|
||||
"""Negative max_value_bytes cannot disable the process memory boundary."""
|
||||
import langbot.pkg.plugin.handler as handler_module
|
||||
|
||||
runtime_handler = make_handler(app)
|
||||
app.instance_config.data['plugin']['binary_storage']['max_value_bytes'] = -1
|
||||
monkeypatch.setattr(handler_module, '_DEFAULT_BINARY_STORAGE_VALUE_BYTES', 1024)
|
||||
|
||||
response = await runtime_handler.actions[RuntimeToLangBotAction.SET_BINARY_STORAGE.value](
|
||||
self.payload(b'x' * 2048)
|
||||
)
|
||||
|
||||
assert response.code == 0
|
||||
assert app.persistence_mgr.execute_async.await_count == 2
|
||||
assert response.code != 0
|
||||
assert '1024-byte limit' in response.message
|
||||
app.persistence_mgr.execute_async.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_zero_limit_rejects_non_empty_values(self, app):
|
||||
|
||||
Reference in New Issue
Block a user