// Package runtime provides a unified abstraction over container runtimes. // // Sorcery-Go can deploy Essences into different execution environments // (called "Sanctums"). This package defines the Runtime interface that // decouples the Warding, Coven, and Reanimation logic from any specific // container technology. // // Supported runtimes: // - LXC: Traditional system containers (lxc-tools CLI) // - Podman: OCI containers (podman CLI / REST API) // - Firecracker: Lightweight microVMs (Firecracker VMM API via Unix socket) // - BareMetal: Direct filesystem deployment (no container) // // The active runtime is selected at startup via SORCERY_GO_RUNTIME env var // or the Runtime field in the Config struct. Each runtime adapter implements // the Runtime interface, providing a consistent API for container lifecycle // management, process execution, freeze/thaw, and status queries. package runtime import ( "context" "fmt" "time" ) // Type identifies the container runtime backend. type Type string const ( // RuntimeLXC uses the LXC system container tools (lxc-create, lxc-start, etc.) RuntimeLXC Type = "lxc" // RuntimePodman uses the Podman OCI container engine. RuntimePodman Type = "podman" // RuntimeFirecracker uses Firecracker microVMs. RuntimeFirecracker Type = "firecracker" // RuntimeBareMetal deploys directly to the host filesystem (no container). RuntimeBareMetal Type = "baremetal" ) // SanctumStatus describes the current state of a container/sanctum. type SanctumStatus string const ( StatusRunning SanctumStatus = "running" StatusStopped SanctumStatus = "stopped" StatusFrozen SanctumStatus = "frozen" StatusCreating SanctumStatus = "creating" StatusDestroyed SanctumStatus = "destroyed" StatusUnknown SanctumStatus = "unknown" ) // SanctumInfo provides runtime-specific information about a sanctum. type SanctumInfo struct { ID string `json:"id"` Name string `json:"name"` Runtime Type `json:"runtime"` Status SanctumStatus `json:"status"` Arch string `json:"arch"` IP string `json:"ip,omitempty"` PID uint32 `json:"pid,omitempty"` Cgroup string `json:"cgroup,omitempty"` Created time.Time `json:"created"` RootFS string `json:"rootfs,omitempty"` Metadata map[string]string `json:"metadata,omitempty"` } // CreateOpts holds the parameters for creating a new sanctum. type CreateOpts struct { // Name is the human-readable container name. Name string // Image is the base image or template (LXC template, OCI image, rootfs path). Image string // Arch is the target architecture (x86_64, aarch64). Arch string // RootFS is the path to the root filesystem (for baremetal or custom rootfs). RootFS string // NetworkConfig specifies the network attachment. NetworkConfig *NetworkConfig // BindMounts are host paths to bind-mount into the container. BindMounts []BindMount // EnvVars are environment variables to set inside the container. EnvVars map[string]string // Caps is the set of Linux capabilities to retain (empty = drop all). Caps []string // MemoryMB is the memory limit in megabytes (0 = unlimited). MemoryMB uint64 // VCPUs is the number of virtual CPUs (for Firecracker). VCPUs uint32 // KernelPath is the host kernel image path (for Firecracker). KernelPath string // RootDrivePath is the root block device path (for Firecracker). RootDrivePath string // ExtraConfig passes runtime-specific configuration as key-value pairs. ExtraConfig map[string]string } // NetworkConfig specifies network attachment for a sanctum. type NetworkConfig struct { // Type is the network mode (bridge, none, host). Type string // "bridge", "none", "host" // Bridge is the host bridge interface name (e.g., "br0"). Bridge string // MACAddress is the desired MAC address (empty = auto-generate). MACAddress string // IP is the desired IP address (empty = DHCP/auto). IP string } // BindMount represents a host-to-container bind mount. type BindMount struct { // HostPath is the path on the host. HostPath string // ContainerPath is the path inside the container. ContainerPath string // ReadOnly makes the mount read-only. ReadOnly bool } // ExecResult captures the output of a command executed inside a sanctum. type ExecResult struct { ExitCode int Stdout []byte Stderr []byte } // Runtime is the interface that all container runtime backends must implement. // // It provides a unified API for the full lifecycle of a Sanctum: // create, start, stop, freeze/thaw, exec, and destroy. The Warding uses // this interface to manage containers without knowing the underlying runtime. type Runtime interface { // Type returns the runtime type identifier (lxc, podman, firecracker, baremetal). Type() Type // Name returns a human-readable name for this runtime instance. Name() string // Probe checks whether this runtime is available on the host. // Returns nil if the runtime tools/API are accessible. Probe() error // Create provisions a new sanctum with the given options. // Returns the sanctum ID on success. Create(ctx context.Context, opts CreateOpts) (string, error) // Start boots or starts a stopped sanctum. Start(ctx context.Context, sanctumID string) error // Stop gracefully stops a running sanctum. Stop(ctx context.Context, sanctumID string) error // Freeze suspends all processes in a running sanctum (cgroup freezer). Freeze(ctx context.Context, sanctumID string) error // Thaw resumes a frozen sanctum. Thaw(ctx context.Context, sanctumID string) error // Destroy removes a sanctum and all its resources. Destroy(ctx context.Context, sanctumID string) error // Exec runs a command inside a running sanctum and returns the output. Exec(ctx context.Context, sanctumID string, command []string, stdin []byte) (*ExecResult, error) // Status returns the current state and info about a sanctum. Status(ctx context.Context, sanctumID string) (*SanctumInfo, error) // List returns all sanctums managed by this runtime. List(ctx context.Context) ([]*SanctumInfo, error) // CgroupPath returns the cgroup v2 path for a sanctum. // This is used by the eBPF enforcer to attach cgroup filters. // Returns "" if the runtime does not use cgroups (e.g., Firecracker). CgroupPath(sanctumID string) string } // Factory creates a Runtime instance for the given type. // Returns an error if the runtime type is unknown or unavailable. func Factory(rtType Type) (Runtime, error) { switch rtType { case RuntimeLXC: r := NewLXCRuntime() if err := r.Probe(); err != nil { return nil, err } return r, nil case RuntimePodman: r := NewPodmanRuntime() if err := r.Probe(); err != nil { return nil, err } return r, nil case RuntimeFirecracker: r := NewFirecrackerRuntime() if err := r.Probe(); err != nil { return nil, err } return r, nil case RuntimeBareMetal: return NewBareMetalRuntime(), nil default: return nil, fmt.Errorf("runtime: unknown runtime type %q (supported: lxc, podman, firecracker, baremetal)", rtType) } } // AutoDetect tries to find an available runtime on the host. // It probes LXC first, then Podman, then Firecracker, and falls back // to baremetal if none are found. func AutoDetect() (Runtime, error) { candidates := []Type{RuntimeLXC, RuntimePodman, RuntimeFirecracker, RuntimeBareMetal} for _, t := range candidates { r, err := Factory(t) if err == nil { return r, nil } } return NewBareMetalRuntime(), nil }