HTTP service that fetches GitLab repository archives for configured customers, merges them into a single tarball, and returns an encrypted payload. Includes Nix flake for reproducible builds.
96 lines
2.2 KiB
Go
96 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
type rawConfig struct {
|
|
Schema string `toml:"schema"`
|
|
Config struct {
|
|
GitLabURL string `toml:"gitlab_url"`
|
|
GitLabAPIKey string `toml:"gitlab_api_key"`
|
|
} `toml:"config"`
|
|
Customers map[string]rawCustomer `toml:"customers"`
|
|
}
|
|
|
|
type rawCustomer struct {
|
|
Key string `toml:"key"`
|
|
Repos []string `toml:"repos"`
|
|
}
|
|
|
|
type ResolvedConfig struct {
|
|
GitLabURL string
|
|
GitLabAPIKey string
|
|
Customers map[string]ResolvedCustomer
|
|
}
|
|
|
|
type ResolvedCustomer struct {
|
|
Key []byte
|
|
Repos []string
|
|
}
|
|
|
|
func LoadConfig(path string) (*ResolvedConfig, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading config: %w", err)
|
|
}
|
|
|
|
expanded := os.Expand(string(data), os.Getenv)
|
|
|
|
var raw rawConfig
|
|
if err := toml.Unmarshal([]byte(expanded), &raw); err != nil {
|
|
return nil, fmt.Errorf("parsing config: %w", err)
|
|
}
|
|
|
|
if err := validateRawConfig(&raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resolved := &ResolvedConfig{
|
|
GitLabURL: raw.Config.GitLabURL,
|
|
GitLabAPIKey: raw.Config.GitLabAPIKey,
|
|
Customers: make(map[string]ResolvedCustomer, len(raw.Customers)),
|
|
}
|
|
|
|
for name, cust := range raw.Customers {
|
|
key, err := hex.DecodeString(cust.Key)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("customer %q: invalid hex key: %w", name, err)
|
|
}
|
|
resolved.Customers[name] = ResolvedCustomer{
|
|
Key: key,
|
|
Repos: cust.Repos,
|
|
}
|
|
}
|
|
|
|
return resolved, nil
|
|
}
|
|
|
|
func validateRawConfig(raw *rawConfig) error {
|
|
if raw.Schema != "v1" {
|
|
return fmt.Errorf("unsupported schema: %q (expected \"v1\")", raw.Schema)
|
|
}
|
|
if raw.Config.GitLabURL == "" {
|
|
return fmt.Errorf("config.gitlab_url is required")
|
|
}
|
|
if raw.Config.GitLabAPIKey == "" {
|
|
return fmt.Errorf("config.gitlab_api_key is required")
|
|
}
|
|
if len(raw.Customers) == 0 {
|
|
return fmt.Errorf("at least one customer is required")
|
|
}
|
|
for name, cust := range raw.Customers {
|
|
if len(cust.Key) != 64 {
|
|
return fmt.Errorf("customer %q: key must be 64 hex characters (got %d)", name, len(cust.Key))
|
|
}
|
|
if len(cust.Repos) == 0 {
|
|
return fmt.Errorf("customer %q: repos list must not be empty", name)
|
|
}
|
|
}
|
|
return nil
|
|
}
|