sandbox

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 16, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package sandbox provides secure code execution in isolated containers.

Index

Constants

View Source
const (
	// LabelManaged identifies containers created by ethpandaops-panda.
	LabelManaged = "io.ethpandaops-panda.managed"
	// LabelCreatedAt stores the Unix timestamp when the container was created.
	LabelCreatedAt = "io.ethpandaops-panda.created-at"
	// LabelSessionID stores the session ID for session containers.
	LabelSessionID = "io.ethpandaops-panda.session-id"
	// LabelOwnerID stores the owner ID (GitHub user ID) if auth is enabled.
	LabelOwnerID = "io.ethpandaops-panda.owner-id"
)

Container label keys for identifying and managing ethpandaops-panda containers.

Variables

This section is empty.

Functions

func CreateMounts

func CreateMounts(sharedDir, outputDir string) []mount.Mount

CreateMounts creates the volume mounts for sandbox execution. sharedDir is mounted read-only at /shared (contains the script). outputDir is mounted read-write at /output (for generated files).

func SandboxEnvDefaults

func SandboxEnvDefaults() map[string]string

SandboxEnvDefaults returns default environment variables for sandbox execution. These ensure proper operation as the "nobody" user with no home directory.

Types

type BackendType

type BackendType string

BackendType represents the available sandbox backend types.

const (
	// BackendDocker uses standard Docker containers.
	BackendDocker BackendType = "docker"
	// BackendGVisor uses Docker with gVisor runtime for enhanced isolation.
	BackendGVisor BackendType = "gvisor"
)

type ContainerListAll

type ContainerListAll func(ctx context.Context) ([]*SessionContainer, error)

ContainerListAll lists all session containers for cleanup.

type ContainerLister

type ContainerLister func(ctx context.Context, sessionID string) (*SessionContainer, error)

ContainerLister queries Docker for session containers.

type DockerBackend

type DockerBackend struct {
	// contains filtered or unexported fields
}

DockerBackend implements sandbox execution using standard Docker containers.

func NewDockerBackend

func NewDockerBackend(cfg config.SandboxConfig, log logrus.FieldLogger) (*DockerBackend, error)

NewDockerBackend creates a new Docker sandbox backend.

func (*DockerBackend) CanCreateSession

func (b *DockerBackend) CanCreateSession(ctx context.Context, ownerID string) (bool, int, int)

CanCreateSession checks if a new session can be created. Returns (canCreate, currentCount, maxAllowed).

func (*DockerBackend) CreateSession

func (b *DockerBackend) CreateSession(ctx context.Context, ownerID string, env map[string]string) (string, error)

CreateSession creates a new empty session and returns its ID.

func (*DockerBackend) DestroySession

func (b *DockerBackend) DestroySession(ctx context.Context, sessionID, ownerID string) error

DestroySession destroys a session by ID. If ownerID is non-empty, verifies ownership before destroying.

func (*DockerBackend) Execute

Execute runs Python code in a Docker container.

func (*DockerBackend) ListSessions

func (b *DockerBackend) ListSessions(ctx context.Context, ownerID string) ([]SessionInfo, error)

ListSessions returns all active sessions. If ownerID is non-empty, filters by owner.

func (*DockerBackend) Name

func (b *DockerBackend) Name() string

Name returns the backend name.

func (*DockerBackend) SessionsEnabled

func (b *DockerBackend) SessionsEnabled() bool

SessionsEnabled returns whether sessions are enabled.

func (*DockerBackend) Start

func (b *DockerBackend) Start(ctx context.Context) error

Start initializes the Docker client and verifies connectivity.

func (*DockerBackend) Stop

func (b *DockerBackend) Stop(ctx context.Context) error

Stop cleans up any active containers and closes the Docker client.

type ExecuteRequest

type ExecuteRequest struct {
	// Code is the Python code to execute.
	Code string
	// Env contains additional environment variables to set in the sandbox.
	Env map[string]string
	// Timeout overrides the default execution timeout. If zero, uses the config default.
	Timeout time.Duration
	// SessionID is an optional session ID to reuse a persistent container.
	// If empty, a new session is created. If provided, the existing session is reused.
	SessionID string
	// OwnerID is the GitHub user ID that owns the session.
	// Required for session creation and verification.
	OwnerID string
}

ExecuteRequest contains the parameters for code execution.

type ExecutionResult

type ExecutionResult struct {
	// Stdout contains the standard output from execution.
	Stdout string
	// Stderr contains the standard error from execution.
	Stderr string
	// ExitCode is the process exit code (0 = success).
	ExitCode int
	// ExecutionID is a unique identifier for this execution.
	ExecutionID string
	// OutputFiles lists file names created in /output directory.
	OutputFiles []string
	// Metrics contains any metrics reported by the executed code.
	Metrics map[string]any
	// DurationSeconds is the wall-clock execution time.
	DurationSeconds float64

	// Session-related fields (only populated when sessions are enabled).
	// SessionID is the session identifier. Can be used to reuse this session.
	SessionID string
	// SessionFiles lists files persisted in the session's /workspace directory.
	SessionFiles []SessionFile
	// SessionTTLRemaining is the time until this session expires from inactivity.
	SessionTTLRemaining time.Duration
}

ExecutionResult contains the output from code execution.

type GVisorBackend

type GVisorBackend struct {
	*DockerBackend
}

GVisorBackend implements sandbox execution using Docker with gVisor runtime. gVisor provides user-space kernel isolation, making container escapes significantly harder compared to standard Docker. Only available on Linux.

func NewGVisorBackend

func NewGVisorBackend(cfg config.SandboxConfig, log logrus.FieldLogger) (*GVisorBackend, error)

NewGVisorBackend creates a new gVisor sandbox backend.

func (*GVisorBackend) Name

func (b *GVisorBackend) Name() string

Name returns the backend name.

func (*GVisorBackend) Start

func (b *GVisorBackend) Start(ctx context.Context) error

Start initializes the Docker client and verifies gVisor runtime is available.

type SecurityConfig

type SecurityConfig struct {
	// User to run the container as (e.g., "nobody").
	User string
	// ReadonlyRootfs makes the root filesystem read-only.
	ReadonlyRootfs bool
	// DropCapabilities lists Linux capabilities to drop.
	DropCapabilities []string
	// SecurityOpts are additional security options (e.g., "no-new-privileges:true").
	SecurityOpts []string
	// PidsLimit restricts the number of processes in the container.
	PidsLimit int64
	// MemoryLimit in bytes.
	MemoryLimit int64
	// CPUQuota as a percentage of one CPU (100000 = 1 CPU).
	CPUQuota int64
	// CPUPeriod is the CPU CFS scheduler period.
	CPUPeriod int64
	// TmpfsSize is the size of the /tmp tmpfs mount.
	TmpfsSize string
	// Runtime specifies the container runtime (e.g., "" for default, "runsc" for gVisor).
	Runtime string
}

SecurityConfig holds security settings for container execution.

func DefaultSecurityConfig

func DefaultSecurityConfig(memoryLimit string, cpuLimit float64) (*SecurityConfig, error)

DefaultSecurityConfig returns the default security configuration for sandboxed execution. Returns an error if the memory limit cannot be parsed.

func GVisorSecurityConfig

func GVisorSecurityConfig(memoryLimit string, cpuLimit float64) (*SecurityConfig, error)

GVisorSecurityConfig returns security configuration for gVisor-based execution. Returns an error if the memory limit cannot be parsed.

func (*SecurityConfig) ApplyToHostConfig

func (s *SecurityConfig) ApplyToHostConfig(hostConfig *container.HostConfig)

ApplyToHostConfig applies security settings to a Docker HostConfig.

type SecurityConfigFunc

type SecurityConfigFunc func(memoryLimit string, cpuLimit float64) (*SecurityConfig, error)

SecurityConfigFunc is a function that returns security configuration.

type Service

type Service interface {
	// Start initializes the sandbox backend (e.g., connecting to Docker).
	Start(ctx context.Context) error
	// Stop cleans up resources and any active containers.
	Stop(ctx context.Context) error
	// Execute runs Python code in an isolated container.
	Execute(ctx context.Context, req ExecuteRequest) (*ExecutionResult, error)
	// Name returns the backend name for logging/metrics.
	Name() string

	// ListSessions returns all active sessions. If ownerID is non-empty, filters by owner.
	ListSessions(ctx context.Context, ownerID string) ([]SessionInfo, error)
	// CreateSession creates a new empty session and returns its ID.
	CreateSession(ctx context.Context, ownerID string, env map[string]string) (string, error)
	// DestroySession destroys a session by ID.
	// If ownerID is non-empty, verifies ownership before destroying.
	DestroySession(ctx context.Context, sessionID, ownerID string) error
	// CanCreateSession checks if a new session can be created.
	// Returns (canCreate, currentCount, maxAllowed).
	CanCreateSession(ctx context.Context, ownerID string) (bool, int, int)
	// SessionsEnabled returns whether sessions are enabled.
	SessionsEnabled() bool
}

Service defines the interface for sandbox code execution backends.

func New

New creates a new sandbox service based on the configuration.

type Session

type Session struct {
	ID          string
	OwnerID     string // Optional owner ID for session binding
	ContainerID string
	CreatedAt   time.Time
	LastUsed    time.Time
	Env         map[string]string
}

Session represents a persistent sandbox execution environment. This is a transient view constructed from container state, not stored in memory.

type SessionContainer

type SessionContainer struct {
	ContainerID string
	SessionID   string
	OwnerID     string
	CreatedAt   time.Time
}

SessionContainer represents container metadata for session lookup.

type SessionFile

type SessionFile struct {
	Name     string    `json:"name"`
	Size     int64     `json:"size"`
	Modified time.Time `json:"modified"`
}

SessionFile represents a file in the session workspace.

type SessionInfo

type SessionInfo struct {
	ID             string        `json:"session_id"`
	CreatedAt      time.Time     `json:"created_at"`
	LastUsed       time.Time     `json:"last_used"`
	TTLRemaining   time.Duration `json:"ttl_remaining"`
	WorkspaceFiles []SessionFile `json:"workspace_files"`
}

SessionInfo represents information about an active session.

type SessionManager

type SessionManager struct {
	// contains filtered or unexported fields
}

SessionManager manages the lifecycle of persistent sandbox sessions. Session state is stored in container labels; only lastUsed times are kept in memory for TTL tracking. On server restart, sessions survive but get fresh TTL timers.

func NewSessionManager

func NewSessionManager(
	cfg config.SessionConfig,
	log logrus.FieldLogger,
	containerLister ContainerLister,
	containerListAll ContainerListAll,
	cleanupCallback func(ctx context.Context, containerID string) error,
) *SessionManager

NewSessionManager creates a new session manager.

func (*SessionManager) ActiveSessionCount

func (m *SessionManager) ActiveSessionCount(ctx context.Context) int

ActiveSessionCount returns the count of active sessions by querying Docker.

func (*SessionManager) CanCreateSession

func (m *SessionManager) CanCreateSession(ctx context.Context, ownerID string) (bool, int, int)

CanCreateSession checks if a new session can be created. If ownerID is provided, counts only sessions owned by that user. Returns (canCreate, currentCount, maxAllowed).

func (*SessionManager) Destroy

func (m *SessionManager) Destroy(ctx context.Context, sessionID, ownerID string) error

Destroy removes a session and triggers cleanup callback. If ownerID is non-empty, verifies ownership before destroying.

func (*SessionManager) Enabled

func (m *SessionManager) Enabled() bool

Enabled returns whether sessions are enabled.

func (*SessionManager) GenerateSessionID

func (m *SessionManager) GenerateSessionID() string

GenerateSessionID creates a new session ID. The caller is responsible for setting this on the container label.

func (*SessionManager) Get

func (m *SessionManager) Get(ctx context.Context, sessionID string, ownerID string) (*Session, error)

Get retrieves a session by ID and updates its last used timestamp. ownerID is optional - when provided, ownership is verified. Session state is queried from Docker; only lastUsed is tracked in memory.

func (*SessionManager) GetLastUsed

func (m *SessionManager) GetLastUsed(sessionID string) time.Time

GetLastUsed returns the last used time for a session. Returns the zero time if the session hasn't been accessed since server start.

func (*SessionManager) MaxSessions

func (m *SessionManager) MaxSessions() int

MaxSessions returns the configured maximum number of sessions.

func (*SessionManager) RecordAccess

func (m *SessionManager) RecordAccess(sessionID string)

RecordAccess records an access time for a session (for TTL tracking).

func (*SessionManager) Start

func (m *SessionManager) Start(ctx context.Context) error

Start begins the background cleanup goroutine.

func (*SessionManager) Stop

func (m *SessionManager) Stop(ctx context.Context) error

Stop terminates the cleanup goroutine and destroys all active sessions.

func (*SessionManager) TTLRemaining

func (m *SessionManager) TTLRemaining(sessionID string) time.Duration

TTLRemaining returns the time remaining until the session expires from inactivity. Returns the full TTL if session hasn't been accessed yet (e.g., after server restart).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL