# Copyright 2025 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Pydantic schemas for OpenSandbox Lifecycle API.
This module defines data models based on the OpenAPI specification
for request/response validation and serialization.
"""
from datetime import datetime
from typing import Dict, List, Literal, Optional
from pydantic import BaseModel, Field, RootModel, model_validator
# ============================================================================
# Image Specification
# ============================================================================
class ImageAuth(BaseModel):
"""
Registry authentication credentials for private container registries.
"""
username: str = Field(..., description="Registry username or service account")
password: str = Field(..., description="Registry password or authentication token")
class ImageSpec(BaseModel):
"""
Container image specification for sandbox provisioning.
Supports public registry images and private registry images with authentication.
"""
uri: str = Field(
...,
description="Container image URI in standard format (e.g., 'python:3.11', 'gcr.io/my-project/app:v1.0')",
)
auth: Optional[ImageAuth] = Field(
None,
description="Registry authentication credentials (required for private registries)",
)
class PlatformSpec(BaseModel):
"""
Runtime platform constraint for scheduling/provisioning.
"""
os: str = Field(
...,
description="Target operating system (for example 'linux').",
)
arch: str = Field(
...,
description="Target CPU architecture (for example 'amd64' or 'arm64').",
)
# ============================================================================
# Resource Limits
# ============================================================================
class ResourceLimits(RootModel[Dict[str, str]]):
"""
Runtime resource constraints as key-value pairs.
Similar to Kubernetes resource specifications, allows flexible definition
of resource limits. Common resource types include cpu, memory, and gpu.
"""
root: Dict[str, str] = Field(
default_factory=dict,
example={"cpu": "500m", "memory": "512Mi", "gpu": "1"},
)
class NetworkRule(BaseModel):
"""
Egress rule: allow/deny a specific domain or wildcard.
"""
action: str = Field(..., description="Whether to allow or deny matching targets (allow | deny).")
target: str = Field(
...,
description="FQDN or wildcard domain (e.g., 'example.com', '*.example.com').",
min_length=1,
)
class Config:
populate_by_name = True
class NetworkPolicy(BaseModel):
"""
Egress network policy matching the sidecar /policy payload.
"""
default_action: Optional[str] = Field(
default=None,
alias="defaultAction",
description="Default action when no egress rule matches (allow | deny). If omitted, sidecar defaults to deny.",
)
egress: list[NetworkRule] = Field(
default_factory=list,
description="Ordered egress rules. Empty/omitted yields allow-all at startup.",
)
class Config:
populate_by_name = True
class CredentialProxyConfig(BaseModel):
"""
Credential proxy startup options.
"""
enabled: bool = Field(
False,
description=(
"When true, the server enables transparent MITM support required by "
"Credential Vault injection. Plain egress network policy does not enable "
"transparent MITM unless this option is set."
),
)
class Config:
populate_by_name = True
# ============================================================================
# Volume Definitions
# ============================================================================
class Host(BaseModel):
"""
Host path bind mount backend.
Maps a directory on the host filesystem into the container.
Only available when the runtime supports host mounts.
Security note: Host paths are restricted by server-side allowlist.
Users must specify paths under permitted prefixes.
"""
path: str = Field(
...,
description="Absolute path on the host filesystem to mount.",
pattern=r"^(/|[A-Za-z]:[\\/])",
)
class PVC(BaseModel):
"""
Platform-managed named volume backend.
A runtime-neutral abstraction for referencing a platform-managed named volume.
If ``createIfNotExists`` is true (the default) and the volume does not
yet exist, it will be created automatically using the provisioning hints below.
- Kubernetes: maps to a PersistentVolumeClaim in the same namespace.
- Docker: maps to a Docker named volume (created via ``docker volume create``).
"""
claim_name: str = Field(
...,
alias="claimName",
description=(
"Name of the volume on the target platform. "
"In Kubernetes this is the PVC name; in Docker this is the named volume name."
),
pattern=r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$",
max_length=253,
)
create_if_not_exists: bool = Field(
True,
alias="createIfNotExists",
description=(
"When true, the volume is automatically created if it does not exist. "
"When false, referencing a non-existent volume fails with an error."
),
)
delete_on_sandbox_termination: bool = Field(
False,
alias="deleteOnSandboxTermination",
description=(
"When true, the volume is automatically removed when the sandbox is "
"deleted. Only applies to volumes that were auto-created by the server "
"on this request; pre-existing volumes are never removed. For "
"Kubernetes, the resulting PVC delete then triggers the bound PV's "
"StorageClass reclaim policy (Retain/Delete)."
),
)
# Provisioning hints — used only when auto-creating a new volume.
# Ignored if the volume already exists on the platform.
storage_class: Optional[str] = Field(
None,
alias="storageClass",
description=(
"Kubernetes StorageClass name for auto-created PVCs. "
"None means use the cluster default. Ignored for Docker volumes."
),
)
storage: Optional[str] = Field(
None,
description=(
"Storage capacity request for auto-created PVCs (e.g. '1Gi', '10Gi'). "
"Defaults to server-side configured value when omitted. "
"Ignored for Docker volumes."
),
pattern=r"^\d+(\.\d+)?(Ki|Mi|Gi|Ti|Pi|Ei)?$",
)
access_modes: Optional[List[str]] = Field(
None,
alias="accessModes",
description=(
"Access modes for auto-created PVCs (e.g. ['ReadWriteOnce']). "
"Defaults to ['ReadWriteOnce'] when omitted. Ignored for Docker volumes."
),
)
class Config:
populate_by_name = True
class OSSFS(BaseModel):
"""
Alibaba Cloud OSS mount backend via ossfs.
The runtime mounts a host-side OSS path under ``storage.ossfs_mount_root``
and then bind-mounts the resolved path into the sandbox container. Prefix
selection is expressed via ``Volume.subPath``.
In Docker runtime, OSSFS backend requires the server host to be Linux with FUSE support.
"""
bucket: str = Field(
...,
description="OSS bucket name.",
min_length=3,
max_length=63,
)
endpoint: str = Field(
...,
description="OSS endpoint, e.g. 'oss-cn-hangzhou.aliyuncs.com'.",
min_length=1,
)
version: Literal["1.0", "2.0"] = Field(
"2.0",
description="ossfs major version used by runtime mount integration.",
)
options: Optional[List[str]] = Field(
None,
description=(
"Additional ossfs mount options. Runtime encodes options by version: "
"1.0 => 'ossfs ... -o