Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion services/core/tools/e2b-provider/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ An unknown Create is never repeated. A Create whose connection material was lost

## Inspection and cleanup

Inspection uses SDK metadata and ID reads only. SDK `connect` is never used because it can resume paused compute. The version-pinned constructor that restores a client from saved connection material is confined to [`sdk.py`](sdk.py) and covered by a no-connect, no-create test. Resource drift fails inspection but still permits ownership-based cleanup.
Inspection accepts the SDK's nullable sandbox-information domain and checks any reported domain against the configured sandbox domain. This information field never supplies connection material: Create's connection domain must match before any envd request, and restoring saved connection material repeats that check. SDK `connect` is never used because it can resume paused compute. The version-pinned constructor that restores a client from saved connection material is confined to [`sdk.py`](sdk.py) and covered by a no-connect, no-create test. Resource drift fails inspection but still permits ownership-based cleanup.

`CreateSettled` proves that the original Create and bootstrap can no longer mutate; it is independent of `BootstrapComplete`. An empty lookup never settles an unknown Create. Kill destroys every matching sandbox, confirms that none remains and only then records a settled tombstone; it returns `State=absent` with `CreateSettled`. A settled rejected Create with no sandbox IDs proves absence without a cloud request, so GetInfo and Kill still succeed when the key is invalid. Ordinary missing compute has no such proof.

Expand Down
11 changes: 7 additions & 4 deletions services/core/tools/e2b-provider/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,17 @@ def owns(self, cloud):
raise Failure('ownership')
return cloud

def check_domain(self, cloud):
def check_domain(self, sandbox_domain):
domain = self.options()['domain']
sandbox_domain = cloud.sandbox_domain
if not isinstance(sandbox_domain, str) or not (
sandbox_domain == domain or sandbox_domain.endswith('.' + domain)):
raise Failure('ownership')

def qualified(self, cloud):
self.check_domain(cloud)
# SDK information reads may omit the domain; they never supply the
# connection material used for envd requests.
if cloud.sandbox_domain is not None:
self.check_domain(cloud.sandbox_domain)
template = self.config['Template'].split(':', 1)[0]
if cloud.template_id not in (template, self.config['Template']):
raise Failure('invalid')
Expand Down Expand Up @@ -170,6 +172,7 @@ def client(self, cloud):
material = (self.receipt.data or {}).get('connection')
if not material or material['sandbox_id'] != cloud.sandbox_id:
raise Failure('unconfirmed')
self.check_domain(material['sandbox_domain'])
return restore(material, self.options())

def inspect(self):
Expand Down Expand Up @@ -218,7 +221,7 @@ def create(self):
raise Failure('unconfirmed') from None
self.receipt.save(status='created', ids=[cloud.sandbox_id], connection=connection_material(cloud))
# A create response must not steer envd traffic to an unrelated host.
self.check_domain(cloud)
self.check_domain(cloud.sandbox_domain)
# SDK Create returns connection material, but no metadata or resources.
# Read its exact ID before writing credentials, even when Core adopts the
# template's resources and does not supply explicit limits.
Expand Down
113 changes: 109 additions & 4 deletions services/core/tools/e2b-provider/provider_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from unittest.mock import Mock, patch
from uuid import uuid4

from e2b import SandboxState
from e2b import SandboxInfo, SandboxState
from e2b.api.client.models.sandbox_detail import SandboxDetail
from e2b.exceptions import AuthenticationException, SandboxNotFoundException

from provider import Provider
Expand Down Expand Up @@ -47,17 +48,121 @@ def setUp(self):
self.patch.start()
self.addCleanup(self.patch.stop)
self.runtime = patch('provider.restore', return_value=self.cloud)
self.runtime.start()
self.restore_mock = self.runtime.start()
self.addCleanup(self.runtime.stop)
self.command = patch('provider.run', return_value=0)
self.command.start()
self.run_mock = self.command.start()
self.addCleanup(self.command.stop)

def call(self, operation):
return Provider(dict(self.request, Operation=operation)).execute()

def record(self):
return json.loads(next(Path(self.temporary.name).glob('*.json')).read_text())
return json.loads(next(Path(self.config['StateDir']).glob('*.json')).read_text())

def sdk_info(self, **fields):
resources = self.config.get('Resources') or {'cpus': 2, 'memory_mib': 2048}
wire = dict(templateID=self.config['Template'].split(':', 1)[0], sandboxID=self.cloud.sandbox_id,
clientID='fixture', startedAt=datetime.now(timezone.utc).isoformat(),
endAt=self.request['Deadline'], envdVersion='0.5.0', cpuCount=resources['cpus'],
memoryMB=resources['memory_mib'], diskSizeMB=4096, state='running', metadata=self.cloud.metadata,
**fields)
return SandboxInfo._from_sandbox_detail(SandboxDetail.from_dict(wire))

def test_sdk_nullable_info_domain_allows_create_inspect_renew_and_cleanup(self):
self.config['Resources'] = {'cpus': 2, 'memory_mib': 2048}
self.api.get_info.return_value = self.sdk_info(domain=None)
self.assertIsNone(self.api.get_info.return_value.sandbox_domain)
self.assertEqual(self.call('create')['ErrorCode'], '')
# The SDK also maps an omitted detail domain to None.
self.api.get_info.return_value = self.sdk_info()
self.assertIsNone(self.api.get_info.return_value.sandbox_domain)
for operation in ('inspect', 'renew'):
result = self.call(operation)
self.assertEqual(result['ErrorCode'], '')
self.assertEqual(result['Info']['State'], 'running')
self.assertTrue(result['Info']['BootstrapComplete'])
self.assertEqual(self.record()['connection']['sandbox_domain'], 'e2b.app')
self.api.set_timeout.assert_called_once()
self.api.kill.side_effect = lambda *args, **kwargs: setattr(
self.api.get_info, 'side_effect', SandboxNotFoundException())
result = self.call('kill')
self.assertEqual(result['ErrorCode'], '')
self.assertEqual(result['Info']['State'], 'absent')
self.assertTrue(result['Info']['CreateSettled'])
self.api.kill.assert_called_once()
self.api.connect.assert_not_called()

def test_sdk_info_reported_domain_remains_checked_before_credentials(self):
self.api.get_info.return_value = self.sdk_info(domain='foreign.example')
self.assertEqual(self.call('create')['ErrorCode'], 'ownership')
self.assertEqual(self.record()['status'], 'configuration_rejected')
self.cloud.files.write.assert_not_called()
self.cloud.files.read.assert_not_called()
self.run_mock.assert_not_called()

def test_sdk_info_foreign_domain_blocks_inspect_and_renew(self):
self.api.get_info.return_value = self.sdk_info(domain=None)
self.assertEqual(self.call('create')['ErrorCode'], '')
self.api.get_info.return_value = self.sdk_info(domain='foreign.example')
for operation in ('inspect', 'renew'):
self.assertEqual(self.call(operation)['ErrorCode'], 'ownership')
self.api.set_timeout.assert_not_called()

def test_sdk_null_info_does_not_relax_owner_template_or_resource_checks(self):
self.config['Resources'] = {'cpus': 2, 'memory_mib': 2048}
for field, value, error in [('metadata', {}, 'ownership'),
('template_id', 'other-template', 'invalid'),
('cpu_count', 1, 'invalid'), ('memory_mb', 1024, 'invalid')]:
with self.subTest(field=field):
info = self.sdk_info(domain=None)
setattr(info, field, value)
self.api.get_info.return_value = info
with tempfile.TemporaryDirectory() as directory:
self.config['StateDir'] = directory
self.assertEqual(self.call('create')['ErrorCode'], error)
self.assertEqual(self.call('inspect')['ErrorCode'], error)
self.assertEqual(self.call('renew')['ErrorCode'], error)
self.api.set_timeout.assert_not_called()
self.cloud.files.write.assert_not_called()
self.cloud.files.read.assert_not_called()

def test_nullable_info_cannot_restore_rejected_create_connection(self):
self.api.get_info.return_value = self.sdk_info(domain=None)
for domain in (None, '', 'foreign.example', 'e2b.app.foreign.example'):
with self.subTest(domain=domain):
with tempfile.TemporaryDirectory() as directory:
self.config['StateDir'] = directory
self.cloud.sandbox_domain = domain
self.assertEqual(self.call('create')['ErrorCode'], 'ownership')
self.assertEqual(self.record()['ids'], ['owned-id'])
self.assertEqual(self.call('inspect')['ErrorCode'], 'ownership')
self.assertEqual(self.call('renew')['ErrorCode'], 'ownership')
self.api.set_timeout.assert_not_called()
self.cloud.files.write.assert_not_called()
self.cloud.files.read.assert_not_called()
self.run_mock.assert_not_called()
self.restore_mock.assert_not_called()

def test_lost_create_with_null_info_is_discovered_without_bootstrap_replay(self):
self.api.create.side_effect = TimeoutError()
self.assertEqual(self.call('create')['ErrorCode'], 'unconfirmed')
info = self.sdk_info(domain=None)
paginator = SimpleNamespace(has_next=True)
def next_items(**options):
paginator.has_next = False
return [info]
paginator.next_items = next_items
self.api.list.return_value = paginator
result = self.call('inspect')
self.assertEqual(result['ErrorCode'], '')
self.assertFalse(result['Info']['BootstrapComplete'])
self.assertFalse(result['Info']['CreateSettled'])
self.assertEqual(self.record()['ids'], [info.sandbox_id])
self.assertEqual(self.call('create')['ErrorCode'], 'exists')
self.cloud.files.write.assert_not_called()
self.cloud.files.read.assert_not_called()
self.api.connect.assert_not_called()

def test_create_recover_and_never_replay(self):
result = self.call('create')
Expand Down
Loading