مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت. تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
129 lines
3.3 KiB
Python
129 lines
3.3 KiB
Python
"""Sandbox domain: templates, workspaces, sessions, commands, snapshots, limits.
|
|
|
|
The host machine must never execute tenant code. Every command flows through a
|
|
SandboxProviderPort adapter and is bounded by a timeout and an output cap.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
from enum import StrEnum
|
|
|
|
from app.domain.base import new_id, utcnow
|
|
|
|
|
|
class SandboxProviderKind(StrEnum):
|
|
MOCK = "mock"
|
|
DAYTONA = "daytona"
|
|
E2B = "e2b"
|
|
|
|
|
|
class WorkspaceStatus(StrEnum):
|
|
PENDING = "pending"
|
|
READY = "ready"
|
|
STOPPED = "stopped"
|
|
DESTROYED = "destroyed"
|
|
FAILED = "failed"
|
|
|
|
|
|
class SessionStatus(StrEnum):
|
|
STARTING = "starting"
|
|
RUNNING = "running"
|
|
PAUSED = "paused"
|
|
STOPPED = "stopped"
|
|
FAILED = "failed"
|
|
|
|
|
|
class NetworkPolicy(StrEnum):
|
|
DENY_ALL = "deny_all"
|
|
ALLOWLIST = "allowlist"
|
|
OPEN = "open"
|
|
|
|
|
|
@dataclass(slots=True, kw_only=True)
|
|
class SandboxTemplate:
|
|
name: str
|
|
provider: str = SandboxProviderKind.MOCK
|
|
image: str = "python:3.13-slim"
|
|
description: str = ""
|
|
default_cpu: float = 1.0
|
|
default_memory_mb: int = 1024
|
|
default_disk_mb: int = 2048
|
|
id: str = field(default_factory=new_id)
|
|
is_system: bool = True
|
|
created_at: datetime = field(default_factory=utcnow)
|
|
|
|
|
|
@dataclass(slots=True, kw_only=True)
|
|
class Workspace:
|
|
organization_id: str
|
|
project_id: str
|
|
template_id: str
|
|
provider: str = SandboxProviderKind.MOCK
|
|
external_workspace_id: str | None = None
|
|
status: WorkspaceStatus = WorkspaceStatus.PENDING
|
|
id: str = field(default_factory=new_id)
|
|
created_at: datetime = field(default_factory=utcnow)
|
|
|
|
|
|
@dataclass(slots=True, kw_only=True)
|
|
class SandboxSession:
|
|
workspace_id: str
|
|
external_session_id: str | None = None
|
|
status: SessionStatus = SessionStatus.STARTING
|
|
id: str = field(default_factory=new_id)
|
|
started_at: datetime = field(default_factory=utcnow)
|
|
stopped_at: datetime | None = None
|
|
last_active_at: datetime = field(default_factory=utcnow)
|
|
|
|
|
|
@dataclass(slots=True, kw_only=True)
|
|
class CommandRun:
|
|
session_id: str
|
|
command: str
|
|
exit_code: int | None = None
|
|
stdout_ref: str = ""
|
|
stderr_ref: str = ""
|
|
duration_ms: int = 0
|
|
truncated: bool = False
|
|
id: str = field(default_factory=new_id)
|
|
created_at: datetime = field(default_factory=utcnow)
|
|
|
|
@property
|
|
def succeeded(self) -> bool:
|
|
return self.exit_code == 0
|
|
|
|
|
|
@dataclass(slots=True, kw_only=True)
|
|
class Snapshot:
|
|
workspace_id: str
|
|
name: str
|
|
external_snapshot_id: str | None = None
|
|
id: str = field(default_factory=new_id)
|
|
created_at: datetime = field(default_factory=utcnow)
|
|
|
|
|
|
@dataclass(slots=True, kw_only=True)
|
|
class PreviewUrl:
|
|
workspace_id: str
|
|
port: int
|
|
url: str
|
|
id: str = field(default_factory=new_id)
|
|
created_at: datetime = field(default_factory=utcnow)
|
|
|
|
|
|
@dataclass(slots=True, kw_only=True)
|
|
class SandboxResourceLimit:
|
|
"""Limits are stored in policy, never trusted from the caller."""
|
|
|
|
cpu: float = 1.0
|
|
memory_mb: int = 1024
|
|
disk_mb: int = 2048
|
|
timeout_seconds: int = 120
|
|
max_output_bytes: int = 200_000
|
|
network_policy: NetworkPolicy = NetworkPolicy.DENY_ALL
|
|
scope: str = "organization"
|
|
scope_id: str | None = None
|
|
id: str = field(default_factory=new_id)
|