Implement SAND-WP-0002 meta-framework foundation (T01–T09)
Add meta-framework spec, pydantic schemas, profile/extension YAML, extension registry, ext.compose-ssh backend, SandboxManager with State Hub events, CLI commands, integration docs, capability registry entry, and compose-e2e runbook. Nine unit tests pass. T10 remote smoke test remains for operator.
This commit is contained in:
parent
b0a57cf9d3
commit
d6d3155792
28 changed files with 1796 additions and 15 deletions
147
src/sandboxer/models.py
Normal file
147
src/sandboxer/models.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
"""Pydantic schemas for profiles, extensions, and sandbox lifecycle."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from enum import StrEnum
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ActorType(StrEnum):
|
||||
ADM = "adm"
|
||||
AGT = "agt"
|
||||
ATM = "atm"
|
||||
|
||||
|
||||
class SandboxState(StrEnum):
|
||||
REQUESTED = "requested"
|
||||
PROVISIONING = "provisioning"
|
||||
READY = "ready"
|
||||
ACTIVE = "active"
|
||||
EXPIRED = "expired"
|
||||
FAILED = "failed"
|
||||
DESTROYING = "destroying"
|
||||
DESTROYED = "destroyed"
|
||||
|
||||
|
||||
class RouteStrategy(StrEnum):
|
||||
PREFER_SELF_HOSTED = "prefer-self-hosted"
|
||||
LOWEST_COST = "lowest-cost"
|
||||
LOWEST_LATENCY = "lowest-latency"
|
||||
EXPLICIT = "explicit"
|
||||
|
||||
|
||||
class Consumer(BaseModel):
|
||||
actor: ActorType
|
||||
project: str
|
||||
session_id: str | None = None
|
||||
run_id: str | None = None
|
||||
|
||||
|
||||
class IsolationSpec(BaseModel):
|
||||
level: Literal["container", "microvm", "policy"] = "container"
|
||||
|
||||
|
||||
class NetworkSpec(BaseModel):
|
||||
default: Literal["deny", "allow"] = "deny"
|
||||
egress: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class WorkspaceSpec(BaseModel):
|
||||
mode: Literal["mirror", "remote-canonical"] = "remote-canonical"
|
||||
access: Literal["none", "ro", "rw"] = "rw"
|
||||
|
||||
|
||||
class TtlSpec(BaseModel):
|
||||
default: str = "4h"
|
||||
max: str = "24h"
|
||||
idle_reap: str | None = None
|
||||
|
||||
|
||||
class ResourceSpec(BaseModel):
|
||||
cpu: str | None = None
|
||||
memory_mb: int | None = None
|
||||
|
||||
|
||||
class SetupSpec(BaseModel):
|
||||
instructions: str = ""
|
||||
secret_refs: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PlacementSpec(BaseModel):
|
||||
prefer: list[str] = Field(default_factory=list)
|
||||
fallback: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ReachabilitySpec(BaseModel):
|
||||
tunnel: str = "ops-bridge"
|
||||
identity: str = "ops-warden"
|
||||
|
||||
|
||||
class ProfileMetadata(BaseModel):
|
||||
cost_class: Literal["self-hosted", "saas-metered"] = "self-hosted"
|
||||
latency_class: str = "standard"
|
||||
|
||||
|
||||
class Profile(BaseModel):
|
||||
id: str
|
||||
version: str
|
||||
extension: str
|
||||
isolation: IsolationSpec = Field(default_factory=IsolationSpec)
|
||||
network: NetworkSpec = Field(default_factory=NetworkSpec)
|
||||
workspace: WorkspaceSpec = Field(default_factory=WorkspaceSpec)
|
||||
scope_default: Literal["session", "agent", "shared"] = "session"
|
||||
ttl: TtlSpec = Field(default_factory=TtlSpec)
|
||||
resources: ResourceSpec = Field(default_factory=ResourceSpec)
|
||||
setup: SetupSpec = Field(default_factory=SetupSpec)
|
||||
placement: PlacementSpec = Field(default_factory=PlacementSpec)
|
||||
reachability: ReachabilitySpec = Field(default_factory=ReachabilitySpec)
|
||||
metadata: ProfileMetadata = Field(default_factory=ProfileMetadata)
|
||||
|
||||
|
||||
class ExtensionCapabilities(BaseModel):
|
||||
isolation_levels: list[str] = Field(default_factory=lambda: ["container"])
|
||||
regions: list[str] = Field(default_factory=list)
|
||||
persistence: bool = False
|
||||
pricing_model: Literal["self-hosted", "metered"] = "self-hosted"
|
||||
|
||||
|
||||
class Extension(BaseModel):
|
||||
id: str
|
||||
title: str
|
||||
description: str = ""
|
||||
handler: str
|
||||
capabilities: ExtensionCapabilities = Field(default_factory=ExtensionCapabilities)
|
||||
config: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class SandboxCreateRequest(BaseModel):
|
||||
profile: str
|
||||
inputs: dict[str, str] = Field(default_factory=dict)
|
||||
consumer: Consumer
|
||||
ttl: str | None = None
|
||||
|
||||
|
||||
class Reachability(BaseModel):
|
||||
ssh: str | None = None
|
||||
remote_dir: str | None = None
|
||||
compose_project: str | None = None
|
||||
host: str | None = None
|
||||
|
||||
|
||||
class SandboxStatus(BaseModel):
|
||||
sandbox_id: str
|
||||
profile_id: str
|
||||
extension_id: str
|
||||
state: SandboxState
|
||||
consumer: Consumer
|
||||
host: str | None = None
|
||||
reachability: Reachability | None = None
|
||||
inputs: dict[str, str] = Field(default_factory=dict)
|
||||
error: str | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
ready_at: datetime | None = None
|
||||
destroyed_at: datetime | None = None
|
||||
Loading…
Add table
Add a link
Reference in a new issue