ollie/cmd/toolsrv/internal/sandbox/config.go

130 lines
3.1 KiB
Go

package sandbox
import (
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"ollie/util"
"gopkg.in/yaml.v3"
)
// Sandbox prepares a command for restricted execution.
type Sandbox interface {
Command(originalCmd []string, cwd string, env map[string]string) ([]string, error)
}
// Config represents the sandbox configuration
type Config struct {
General GeneralConfig `yaml:"general"`
Filesystem FilesystemConfig `yaml:"filesystem"`
Network NetworkConfig `yaml:"network"`
Env []string `yaml:"env"`
Advanced AdvancedConfig `yaml:"advanced"`
}
// GeneralConfig contains general sandbox settings
type GeneralConfig struct {
BestEffort bool `yaml:"best_effort"`
LogLevel string `yaml:"log_level"`
}
// FilesystemConfig contains filesystem permission settings
type FilesystemConfig struct {
RO []string `yaml:"ro"` // Read-only
ROX []string `yaml:"rox"` // Read-only with execute
RW []string `yaml:"rw"` // Read-write
RWX []string `yaml:"rwx"` // Read-write with execute
}
// NetworkConfig contains network permission settings
type NetworkConfig struct {
Enabled bool `yaml:"enabled"`
Unrestricted bool `yaml:"unrestricted"`
BindTCP []string `yaml:"bind_tcp"`
ConnectTCP []string `yaml:"connect_tcp"`
}
// AdvancedConfig contains compatibility settings retained in the policy format.
type AdvancedConfig struct {
LDD bool `yaml:"ldd"`
AddExec bool `yaml:"add_exec"`
}
// EnvFunc looks up an environment variable by name.
type EnvFunc func(string) string
// expandPath replaces template variables with actual values using getenv for lookups.
func expandPath(pattern, cwd string, getenv EnvFunc) string {
s := pattern
s = strings.ReplaceAll(s, "{CWD}", cwd)
re := regexp.MustCompile(`\{([A-Z_][A-Z0-9_]*)\}`)
s = re.ReplaceAllStringFunc(s, func(match string) string {
varName := match[1 : len(match)-1]
home := getenv("HOME")
switch varName {
case "HOME":
if home != "" {
return home
}
case "TMPDIR":
if tmpdir := getenv("TMPDIR"); tmpdir != "" {
return tmpdir
}
return "/tmp"
case "XDG_CONFIG_HOME":
if xdg := getenv("XDG_CONFIG_HOME"); xdg != "" {
return xdg
}
return filepath.Join(home, ".config")
case "XDG_DATA_HOME":
if xdg := getenv("XDG_DATA_HOME"); xdg != "" {
return xdg
}
return filepath.Join(home, ".local/share")
case "XDG_CACHE_HOME":
if xdg := getenv("XDG_CACHE_HOME"); xdg != "" {
return xdg
}
return filepath.Join(home, ".cache")
case "XDG_STATE_HOME":
if xdg := getenv("XDG_STATE_HOME"); xdg != "" {
return xdg
}
return filepath.Join(home, ".local/state")
case "XDG_RUNTIME_DIR":
if xdg := getenv("XDG_RUNTIME_DIR"); xdg != "" {
return xdg
}
return fmt.Sprintf("/run/user/%d", os.Getuid())
}
if val := getenv(varName); val != "" {
return val
}
return match
})
s = util.ExpandHome(s)
return s
}
// LoadSandbox parses a sandbox config from r.
func LoadSandbox(r io.Reader) (*Config, error) {
data, err := io.ReadAll(r)
if err != nil {
return nil, err
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
}
return &cfg, nil
}