diff --git a/config/config.go b/config/config.go index 62c809535..832a3af0c 100644 --- a/config/config.go +++ b/config/config.go @@ -77,6 +77,11 @@ func NewConfig(cfgFile string) (*Config, error) { if err := config.Validate(); err != nil { return nil, fmt.Errorf("error validating config: %w", err) } + // Set proxy environment variables process wide if they are set + // in the config. This overrides any environment variables already set + // by the environment from which GARM was invoked. + config.Proxy.populateEnv() + return &config, nil } @@ -88,6 +93,7 @@ type Config struct { Providers []Provider `toml:"provider,omitempty" json:"provider,omitempty"` JWTAuth JWTAuth `toml:"jwt_auth" json:"jwt-auth"` Logging Logging `toml:"logging" json:"logging"` + Proxy Proxy `toml:"proxy" json:"proxy"` } // Validate validates the config @@ -111,6 +117,10 @@ func (c *Config) Validate() error { return fmt.Errorf("error validating logging config: %w", err) } + if err := c.Proxy.Validate(); err != nil { + return fmt.Errorf("failed to validate proxy settings: %w", err) + } + providerNames := map[string]int{} for _, provider := range c.Providers { @@ -150,6 +160,47 @@ func (c *Config) GetLoggingConfig() Logging { return logging } +type Proxy struct { + HTTPProxy string `toml:"http_proxy" json:"http_proxy"` + HTTPSProxy string `toml:"https_proxy" json:"https_proxy"` + NoProxy string `toml:"no_proxy" json:"no_proxy"` +} + +func (p *Proxy) Validate() error { + if p.HTTPProxy != "" { + _, err := url.ParseRequestURI(p.HTTPProxy) + if err != nil { + return fmt.Errorf("invalid http_proxy: %w", err) + } + } + + if p.HTTPSProxy != "" { + _, err := url.ParseRequestURI(p.HTTPSProxy) + if err != nil { + return fmt.Errorf("invalid https_proxy: %w", err) + } + } + + return nil +} + +func (p *Proxy) populateEnv() { + if p.HTTPProxy != "" { + os.Setenv("http_proxy", p.HTTPProxy) + os.Setenv("HTTP_PROXY", p.HTTPProxy) + } + + if p.HTTPSProxy != "" { + os.Setenv("https_proxy", p.HTTPSProxy) + os.Setenv("HTTPS_PROXY", p.HTTPSProxy) + } + + if p.NoProxy != "" { + os.Setenv("no_proxy", p.NoProxy) + os.Setenv("NO_PROXY", p.NoProxy) + } +} + type Logging struct { // LogFile is the location of the log file. LogFile string `toml:"log_file,omitempty" json:"log-file"` diff --git a/config/external.go b/config/external.go index ca98bdfb6..cbb8978ef 100644 --- a/config/external.go +++ b/config/external.go @@ -52,16 +52,30 @@ type External struct { func (e *External) GetEnvironmentVariables() []string { envVars := []string{} + seen := map[string]struct{}{} + proxyVars := []string{ + "http_proxy", + "https_proxy", + "no_proxy", + "HTTP_PROXY", + "HTTPS_PROXY", + "NO_PROXY", + } + lookups := e.EnvironmentVariables + lookups = append(lookups, proxyVars...) - for _, configuredEnvVars := range e.EnvironmentVariables { + for _, configuredEnvVars := range lookups { + if _, ok := seen[configuredEnvVars]; ok { + continue + } // discover environment variables for _, k := range os.Environ() { variable := strings.SplitN(k, "=", 2) - if strings.HasPrefix(variable[0], configuredEnvVars) && - !strings.HasPrefix(variable[0], EnvironmentVariablePrefix) { + if strings.HasPrefix(variable[0], configuredEnvVars) && !strings.HasPrefix(variable[0], EnvironmentVariablePrefix) { envVars = append(envVars, k) } } + seen[configuredEnvVars] = struct{}{} } return envVars }