Files
TA-Deployment-Broker/internal/app/config.go
T
David Schroeder 69cc236635 update
2026-07-25 14:51:48 -05:00

154 lines
4.3 KiB
Go

package app
import (
"fmt"
"net/url"
"os"
"strconv"
"strings"
"time"
)
type Config struct {
ListenAddr string
PublicURL *url.URL
DatabaseDSN string
GiteaURL *url.URL
GiteaClientID string
GiteaClientSecret string
GiteaPackageOwner string
GiteaPackageUser string
GiteaPackageToken string
GiteaWriteUser string
GiteaWriteToken string
AllowedGiteaUsers map[string]struct{}
CookieSecret []byte
DefaultDuration time.Duration
DefaultHostLimit int
MaxHostLimit int
MaxUploadBytes int64
TrustProxyHeaders bool
}
func LoadConfig() (Config, error) {
var cfg Config
var err error
cfg.ListenAddr = envDefault("TAPM_LISTEN_ADDR", ":8080")
cfg.DatabaseDSN = os.Getenv("TAPM_DATABASE_DSN")
cfg.GiteaClientID = os.Getenv("TAPM_GITEA_CLIENT_ID")
cfg.GiteaClientSecret = os.Getenv("TAPM_GITEA_CLIENT_SECRET")
cfg.GiteaPackageOwner = envDefault("TAPM_GITEA_PACKAGE_OWNER", "TAI")
cfg.GiteaPackageUser = os.Getenv("TAPM_GITEA_PACKAGE_USERNAME")
cfg.GiteaPackageToken = os.Getenv("TAPM_GITEA_PACKAGE_TOKEN")
cfg.GiteaWriteUser = os.Getenv("TAPM_GITEA_PACKAGE_WRITE_USERNAME")
cfg.GiteaWriteToken = os.Getenv("TAPM_GITEA_PACKAGE_WRITE_TOKEN")
cfg.CookieSecret = []byte(os.Getenv("TAPM_COOKIE_SECRET"))
cfg.PublicURL, err = parseAbsoluteURL("TAPM_PUBLIC_URL")
if err != nil {
return cfg, err
}
cfg.GiteaURL, err = parseAbsoluteURL("TAPM_GITEA_URL")
if err != nil {
return cfg, err
}
cfg.DefaultDuration, err = time.ParseDuration(
envDefault("TAPM_DEFAULT_DURATION", "3h"),
)
if err != nil || cfg.DefaultDuration <= 0 {
return cfg, fmt.Errorf("TAPM_DEFAULT_DURATION must be positive")
}
cfg.DefaultHostLimit, err = envInt("TAPM_DEFAULT_HOST_LIMIT", 3)
if err != nil {
return cfg, err
}
cfg.MaxHostLimit, err = envInt("TAPM_MAX_HOST_LIMIT", 25)
if err != nil {
return cfg, err
}
if cfg.DefaultHostLimit < 1 || cfg.MaxHostLimit < cfg.DefaultHostLimit {
return cfg, fmt.Errorf("invalid default or maximum host limit")
}
cfg.MaxUploadBytes, err = envInt64("TAPM_MAX_UPLOAD_BYTES", 1<<30)
if err != nil || cfg.MaxUploadBytes < 1<<20 {
return cfg, fmt.Errorf("TAPM_MAX_UPLOAD_BYTES must be at least 1048576")
}
cfg.TrustProxyHeaders, err = strconv.ParseBool(
envDefault("TAPM_TRUST_PROXY_HEADERS", "false"),
)
if err != nil {
return cfg, fmt.Errorf("TAPM_TRUST_PROXY_HEADERS: %w", err)
}
cfg.AllowedGiteaUsers = make(map[string]struct{})
for _, user := range strings.Split(
envDefault("TAPM_ALLOWED_GITEA_USERS", "taiadmin"),
",",
) {
user = strings.ToLower(strings.TrimSpace(user))
if user != "" {
cfg.AllowedGiteaUsers[user] = struct{}{}
}
}
required := map[string]string{
"TAPM_DATABASE_DSN": cfg.DatabaseDSN,
"TAPM_GITEA_CLIENT_ID": cfg.GiteaClientID,
"TAPM_GITEA_CLIENT_SECRET": cfg.GiteaClientSecret,
"TAPM_GITEA_PACKAGE_USERNAME": cfg.GiteaPackageUser,
"TAPM_GITEA_PACKAGE_TOKEN": cfg.GiteaPackageToken,
"TAPM_GITEA_PACKAGE_WRITE_USERNAME": cfg.GiteaWriteUser,
"TAPM_GITEA_PACKAGE_WRITE_TOKEN": cfg.GiteaWriteToken,
}
for name, value := range required {
if strings.TrimSpace(value) == "" {
return cfg, fmt.Errorf("%s is required", name)
}
}
if len(cfg.CookieSecret) < 32 {
return cfg, fmt.Errorf("TAPM_COOKIE_SECRET must contain at least 32 bytes")
}
if len(cfg.AllowedGiteaUsers) == 0 {
return cfg, fmt.Errorf("at least one Gitea user must be allowed")
}
return cfg, nil
}
func parseAbsoluteURL(name string) (*url.URL, error) {
raw := os.Getenv(name)
parsed, err := url.Parse(raw)
if err != nil || parsed.Scheme != "https" || parsed.Host == "" {
return nil, fmt.Errorf("%s must be an absolute HTTPS URL", name)
}
return parsed, nil
}
func envDefault(name, fallback string) string {
if value := os.Getenv(name); value != "" {
return value
}
return fallback
}
func envInt(name string, fallback int) (int, error) {
raw := envDefault(name, strconv.Itoa(fallback))
value, err := strconv.Atoi(raw)
if err != nil {
return 0, fmt.Errorf("%s must be an integer", name)
}
return value, nil
}
func envInt64(name string, fallback int64) (int64, error) {
raw := envDefault(name, strconv.FormatInt(fallback, 10))
value, err := strconv.ParseInt(raw, 10, 64)
if err != nil {
return 0, fmt.Errorf("%s must be an integer", name)
}
return value, nil
}