// Package config loads the agent's configuration from environment variables. package config import ( "errors" "os" "regexp" "strings" ) var masterKeyPattern = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`) // Config holds the agent's runtime configuration. type Config struct { MasterURL string // MASTER_URL, wss://host:port/agent MasterKey string // MASTER_KEY, fingerprint shown in the master UI Token string // AGENT_TOKEN, shown once when the agent was added SelfID string // SELF_ID, defaults to the hostname (= container ID prefix) LogLevel string // LOG_LEVEL, default info } // Load reads and validates the agent configuration. It fails fast so a // misconfigured agent never starts dialling. func Load() (*Config, error) { cfg := &Config{ MasterURL: os.Getenv("MASTER_URL"), MasterKey: os.Getenv("MASTER_KEY"), Token: os.Getenv("AGENT_TOKEN"), SelfID: os.Getenv("SELF_ID"), LogLevel: os.Getenv("LOG_LEVEL"), } switch { case cfg.MasterURL == "": return nil, errors.New("MASTER_URL is required") case !strings.HasPrefix(cfg.MasterURL, "wss://"): return nil, errors.New("MASTER_URL must start with wss://") case cfg.MasterKey == "": return nil, errors.New("MASTER_KEY is required") case !masterKeyPattern.MatchString(cfg.MasterKey): return nil, errors.New("MASTER_KEY must look like sha256:<64 hex>") case cfg.Token == "": return nil, errors.New("AGENT_TOKEN is required") } if cfg.SelfID == "" { cfg.SelfID, _ = os.Hostname() } if cfg.LogLevel == "" { cfg.LogLevel = "info" } return cfg, nil }