From f2fe61652c730b86ff8b92a62e1d86c6ed24dd41 Mon Sep 17 00:00:00 2001 From: Jvst Me Date: Thu, 7 May 2026 21:41:53 +0200 Subject: [PATCH] Forbid exporting the built-in `dstack` Sky gateway --- .../_internal/server/services/exports.py | 7 +++- .../_internal/server/routers/test_exports.py | 35 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/dstack/_internal/server/services/exports.py b/src/dstack/_internal/server/services/exports.py index e6e6ad0ba..3dc2a3b1c 100644 --- a/src/dstack/_internal/server/services/exports.py +++ b/src/dstack/_internal/server/services/exports.py @@ -11,6 +11,7 @@ ResourceNotExistsError, ServerClientError, ) +from dstack._internal.core.models.backends.base import BackendType from dstack._internal.core.models.exports import ( Export, ExportedFleet, @@ -299,8 +300,12 @@ async def add_exported_gateways( raise ServerClientError( f"Gateways {already_exported} are already exported by export {export.name!r}" ) - gateways = await list_project_gateway_models(session=session, project=export.project) + gateways = await list_project_gateway_models( + session=session, project=export.project, load_backend_type=True + ) gateways = [g for g in gateways if g.name in names] + if any(g.backend.type == BackendType.DSTACK for g in gateways): + raise ServerClientError("Exporting the built-in dstack Sky gateway is not allowed") if missing := set(names) - {g.name for g in gateways}: raise ResourceNotExistsError( f"Gateways {missing} not found in project {export.project.name!r}" diff --git a/src/tests/_internal/server/routers/test_exports.py b/src/tests/_internal/server/routers/test_exports.py index 6c6d0da65..5c0e79881 100644 --- a/src/tests/_internal/server/routers/test_exports.py +++ b/src/tests/_internal/server/routers/test_exports.py @@ -5,6 +5,7 @@ from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession +from dstack._internal.core.models.backends.base import BackendType from dstack._internal.core.models.users import GlobalRole, ProjectRole from dstack._internal.server.models import ExportModel from dstack._internal.server.services.projects import add_project_member @@ -210,6 +211,14 @@ async def test_creates_empty_export(self, session: AsyncSession, client: AsyncCl "Fleets ['cloud-fleet'] are cloud fleets. Can only export SSH fleets", id="cloud-fleet", ), + pytest.param( + { + "name": "test-export", + "exported_gateways": ["sky-gateway"], + }, + "Exporting the built-in dstack Sky gateway is not allowed", + id="sky-gateway", + ), pytest.param( { "name": "test-export", @@ -269,6 +278,15 @@ async def test_rejects_invalid_export( backend_id=backend.id, name="exported-gateway", ) + sky_backend = await create_backend( + session=session, project_id=project.id, backend_type=BackendType.DSTACK + ) + await create_gateway( + session=session, + project_id=project.id, + backend_id=sky_backend.id, + name="sky-gateway", + ) not_permitted_project = await create_project( session=session, name="NotPermittedProject", owner=user ) @@ -650,6 +668,14 @@ async def test_can_add_same_entities_as_existing_deleted_ones( "Fleets ['cloud-fleet'] are cloud fleets. Can only export SSH fleets", id="add-cloud-fleet", ), + pytest.param( + { + "name": "test-export", + "add_exported_gateways": ["sky-gateway"], + }, + "Exporting the built-in dstack Sky gateway is not allowed", + id="add-sky-gateway", + ), pytest.param( { "name": "test-export", @@ -810,6 +836,15 @@ async def test_rejects_invalid_update( name="not-exported-fleet", spec=get_fleet_spec(get_ssh_fleet_configuration()), ) + sky_backend = await create_backend( + session=session, project_id=project.id, backend_type=BackendType.DSTACK + ) + await create_gateway( + session=session, + project_id=project.id, + backend_id=sky_backend.id, + name="sky-gateway", + ) not_importer_project = await create_project( session=session, name="NotImporterProject", owner=user )