Files
DoGaMa-serv/internal/agent/agent_config.go
T
tony 46bc90a0e8
CI / validate (pull_request) Failing after 2m30s
feat(release): harden production packaging
2026-08-09 22:11:21 +02:00

77 lines
2.2 KiB
Go

package agent
import (
"bytes"
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
)
// Config contains bootstrap-only settings for the restricted agent.
type Config struct {
ListenAddress string
Secret []byte
AllowedRoots []string
RegistryPath string
DockerSocket string
DockerNetwork string
}
// LoadConfig reads the agent's bootstrap settings and shared secret file.
func LoadConfig() (Config, error) {
tokenFile := environment("DOGAMA_AGENT_TOKEN_FILE", "/var/lib/dogama-agent/secrets/token")
secret, err := readSecretFile(tokenFile)
if err != nil {
return Config{}, err
}
roots := make([]string, 0, 2)
for _, item := range []struct{ name, fallback string }{
{"DOGAMA_ALLOWED_SERVER_ROOT", "/srv/game-servers"},
{"DOGAMA_ALLOWED_BACKUP_ROOT", "/srv/game-backups"},
} {
if value := environment(item.name, item.fallback); value != "" {
roots = append(roots, value)
}
}
if len(roots) == 0 {
return Config{}, errors.New("at least one allowed root is required")
}
config := Config{
ListenAddress: environment("DOGAMA_AGENT_LISTEN_ADDRESS", ":8081"),
Secret: secret,
AllowedRoots: roots,
RegistryPath: environment("DOGAMA_AGENT_REGISTRY_PATH", "/var/lib/dogama-agent/registry.json"),
DockerSocket: environment("DOGAMA_DOCKER_SOCKET", "/var/run/docker.sock"),
DockerNetwork: environment("DOGAMA_DOCKER_NETWORK", "dogama-games"),
}
if !filepath.IsAbs(config.RegistryPath) || !filepath.IsAbs(config.DockerSocket) {
return Config{}, errors.New("registry and Docker socket paths must be absolute")
}
if !regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$`).MatchString(config.DockerNetwork) {
return Config{}, errors.New("docker network name is invalid")
}
return config, nil
}
func readSecretFile(path string) ([]byte, error) {
body, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read agent secret: %w", err)
}
body = bytes.TrimSuffix(body, []byte("\n"))
body = bytes.TrimSuffix(body, []byte("\r"))
if len(body) < 32 || len(body) > 4096 {
return nil, errors.New("agent secret must contain between 32 and 4096 bytes")
}
return body, nil
}
func environment(name, fallback string) string {
if value := os.Getenv(name); value != "" {
return value
}
return fallback
}