From 924ffbae4c7c06bd1e289b472403957aa0504c94 Mon Sep 17 00:00:00 2001 From: Edouard Bonlieu Date: Mon, 1 Dec 2025 12:22:28 +0100 Subject: [PATCH] add registry_secret parameter for private container images --- koyeb/sandbox/sandbox.py | 23 ++++++++++++++++++++++- koyeb/sandbox/utils.py | 10 +++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/koyeb/sandbox/sandbox.py b/koyeb/sandbox/sandbox.py index 5c601712..7b0311da 100644 --- a/koyeb/sandbox/sandbox.py +++ b/koyeb/sandbox/sandbox.py @@ -112,6 +112,7 @@ def create( idle_timeout: int = 300, enable_tcp_proxy: bool = False, privileged: bool = False, + registry_secret: Optional[str] = None, _experimental_enable_light_sleep: bool = False, ) -> Sandbox: """ @@ -136,6 +137,8 @@ def create( - If None: uses default values enable_tcp_proxy: If True, enables TCP proxy for direct TCP access to port 3031 privileged: If True, run the container in privileged mode (default: False) + registry_secret: Name of a Koyeb secret containing registry credentials for + pulling private images. Create the secret via Koyeb dashboard or CLI first. _experimental_enable_light_sleep: If True, uses idle_timeout for light_sleep and sets deep_sleep=3900. If False, uses idle_timeout for deep_sleep (default: False) @@ -145,6 +148,16 @@ def create( Raises: ValueError: If API token is not provided SandboxTimeoutError: If wait_ready is True and sandbox does not become ready within timeout + + Example: + >>> # Public image (default) + >>> sandbox = Sandbox.create() + + >>> # Private image with registry secret + >>> sandbox = Sandbox.create( + ... image="ghcr.io/myorg/myimage:latest", + ... registry_secret="my-ghcr-secret" + ... ) """ if api_token is None: api_token = os.getenv("KOYEB_API_TOKEN") @@ -165,6 +178,7 @@ def create( idle_timeout=idle_timeout, enable_tcp_proxy=enable_tcp_proxy, privileged=privileged, + registry_secret=registry_secret, _experimental_enable_light_sleep=_experimental_enable_light_sleep, ) @@ -193,6 +207,7 @@ def _create_sync( idle_timeout: int = 300, enable_tcp_proxy: bool = False, privileged: bool = False, + registry_secret: Optional[str] = None, _experimental_enable_light_sleep: bool = False, ) -> Sandbox: """ @@ -217,7 +232,9 @@ def _create_sync( app_id = app_response.app.id env_vars = build_env_vars(env) - docker_source = create_docker_source(image, [], privileged=privileged) + docker_source = create_docker_source( + image, [], privileged=privileged, image_registry_secret=registry_secret + ) deployment_definition = create_deployment_definition( name=name, docker_source=docker_source, @@ -851,6 +868,7 @@ async def create( idle_timeout: int = 300, enable_tcp_proxy: bool = False, privileged: bool = False, + registry_secret: Optional[str] = None, _experimental_enable_light_sleep: bool = False, ) -> AsyncSandbox: """ @@ -875,6 +893,8 @@ async def create( - If None: uses default values enable_tcp_proxy: If True, enables TCP proxy for direct TCP access to port 3031 privileged: If True, run the container in privileged mode (default: False) + registry_secret: Name of a Koyeb secret containing registry credentials for + pulling private images. Create the secret via Koyeb dashboard or CLI first. _experimental_enable_light_sleep: If True, uses idle_timeout for light_sleep and sets deep_sleep=3900. If False, uses idle_timeout for deep_sleep (default: False) @@ -907,6 +927,7 @@ async def create( idle_timeout=idle_timeout, enable_tcp_proxy=enable_tcp_proxy, privileged=privileged, + registry_secret=registry_secret, _experimental_enable_light_sleep=_experimental_enable_light_sleep, ), ) diff --git a/koyeb/sandbox/utils.py b/koyeb/sandbox/utils.py index c98af1b0..9448f8a9 100644 --- a/koyeb/sandbox/utils.py +++ b/koyeb/sandbox/utils.py @@ -12,7 +12,6 @@ from koyeb.api import ApiClient, Configuration from koyeb.api.api import AppsApi, CatalogInstancesApi, InstancesApi, ServicesApi -from koyeb.api.exceptions import ApiException, NotFoundException from koyeb.api.models.deployment_definition import DeploymentDefinition from koyeb.api.models.deployment_definition_type import DeploymentDefinitionType from koyeb.api.models.deployment_env import DeploymentEnv @@ -26,7 +25,6 @@ DeploymentScalingTargetSleepIdleDelay, ) from koyeb.api.models.docker_source import DockerSource -from koyeb.api.models.instance_status import InstanceStatus from koyeb.api.models.proxy_port_protocol import ProxyPortProtocol # Setup logging @@ -137,7 +135,10 @@ def build_env_vars(env: Optional[Dict[str, str]]) -> List[DeploymentEnv]: def create_docker_source( - image: str, command_args: List[str], privileged: Optional[bool] = None + image: str, + command_args: List[str], + privileged: Optional[bool] = None, + image_registry_secret: Optional[str] = None, ) -> DockerSource: """ Create Docker source configuration. @@ -146,6 +147,8 @@ def create_docker_source( image: Docker image name command_args: Command and arguments to run (optional, empty list means use image default) privileged: If True, run the container in privileged mode (default: None/False) + image_registry_secret: Name of the secret containing registry credentials + for pulling private images Returns: DockerSource object @@ -155,6 +158,7 @@ def create_docker_source( command=command_args[0] if command_args else None, args=list(command_args[1:]) if len(command_args) > 1 else None, privileged=privileged, + image_registry_secret=image_registry_secret, )