This commit is contained in:
Mayowa Fajobi 2026-02-28 14:06:04 +01:00 committed by GitHub
commit 6991699e21
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 145 additions and 4 deletions

View File

@ -53,6 +53,11 @@ linters:
- revive
path: util/.*\.go$
text: "var-naming: avoid meaningless package names"
# pkg/version conflicts with go/version (added in Go 1.22)
- linters:
- revive
path: pkg/version/.*\.go$
text: "var-naming: avoid package names that conflict with"
- linters:
- prealloc
path: _test\.go

View File

@ -106,6 +106,17 @@ the new config.
oauth2-proxy --alpha-config ./path/to/new/config.yaml --config ./path/to/existing/config.cfg
```
### Validating Alpha Configuration
Use `--config-test` to validate your alpha configuration without starting the proxy:
```bash
oauth2-proxy --config core.cfg --alpha-config alpha.yaml --config-test
```
This is useful for CI/CD pipelines to catch configuration errors before deployment.
See the [Configuration Validation](./overview.md#configuration-validation) section for more details.
### How to use environment variables
The alpha package supports the use of environment variables in place of yaml values, allowing sensitive data to be pulled from somewhere other than the yaml file.

View File

@ -66,11 +66,47 @@ An example [oauth2-proxy.cfg](https://github.com/oauth2-proxy/oauth2-proxy/blob/
### Command Line Options
| Flag | Description |
| ----------- | -------------------- |
| `--config` | path to config file |
| `--version` | print version string |
| Flag | Description |
| ---------------- | ------------------------------------------------------- |
| `--config` | path to config file |
| `--config-test` | test configuration and exit (for CI/CD validation) |
| `--version` | print version string |
## Configuration Validation
The `--config-test` flag validates your configuration file without starting the proxy server. This is useful for:
- **CI/CD pipelines**: Pre-deployment validation
- **Configuration management**: Testing before applying changes
- **Debugging**: Verifying syntax and required fields
### Usage
```bash
# Test legacy config
oauth2-proxy --config /etc/oauth2-proxy.cfg --config-test
# Test alpha config
oauth2-proxy --config /etc/core.cfg --alpha-config /etc/alpha.yaml --config-test
# CI/CD pre-deployment check
oauth2-proxy --config new-config.cfg --config-test && deploy-to-production
```
### Exit Codes
- **0**: Configuration is valid ✅
- **1**: Configuration is invalid (errors printed to stderr) ❌
### Validation Coverage
The `--config-test` flag performs the **same comprehensive validation** as normal startup, including:
- Required fields (client ID, client secret, cookie secret, etc.)
- Syntax validation (TOML/YAML parsing)
- Provider configuration
- Upstream server definitions
- Session store connectivity (e.g., Redis network checks if configured)
**Note**: Cannot be combined with `--convert-config-to-alpha`.
### General Provider Options

14
main.go
View File

@ -26,6 +26,7 @@ func main() {
alphaConfig := configFlagSet.String("alpha-config", "", "path to alpha config file (use at your own risk - the structure in this config file may change between minor releases)")
convertConfig := configFlagSet.Bool("convert-config-to-alpha", false, "if true, the proxy will load configuration as normal and convert existing configuration to the alpha config structure, and print it to stdout")
showVersion := configFlagSet.Bool("version", false, "print version string")
configTest := configFlagSet.Bool("config-test", false, "test the configuration and exit")
configFlagSet.Parse(os.Args[1:])
if *showVersion {
@ -37,11 +38,24 @@ func main() {
logger.Fatal("cannot use alpha-config and convert-config-to-alpha together")
}
if *configTest && *convertConfig {
logger.Fatal("cannot use config-test and convert-config-to-alpha together")
}
opts, err := loadConfiguration(*config, *alphaConfig, configFlagSet, os.Args[1:])
if err != nil {
logger.Fatalf("ERROR: %v", err)
}
if *configTest {
if err = validation.Validate(opts); err != nil {
logger.Errorf("%s", err)
os.Exit(1)
}
fmt.Println("configuration is valid")
return
}
if *convertConfig {
if err := printConvertedConfig(opts); err != nil {
logger.Fatalf("ERROR: could not convert config: %v", err)

View File

@ -7,6 +7,7 @@ import (
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
. "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options/testutil"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util/ptr"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/format"
@ -291,4 +292,78 @@ redirect_url="http://localhost:4180/oauth2/callback"
expectedErr: errors.New("failed to load legacy options: failed to load config: error unmarshalling config: decoding failed due to the following error(s):\n\n'' has invalid keys: unknown_field"),
}),
)
Describe("Config Test Mode", func() {
const validConfig = `
http_address="127.0.0.1:4180"
upstreams="http://httpbin"
client_id="oauth2-proxy"
client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK"
cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
email_domains="example.com"
cookie_secure="false"
redirect_url="http://localhost:4180/oauth2/callback"
`
const invalidConfig = `
http_address="127.0.0.1:4180"
upstreams="http://httpbin"
email_domains="example.com"
cookie_secure="false"
redirect_url="http://localhost:4180/oauth2/callback"
`
writeTempConfig := func(content string) string {
file, err := os.CreateTemp("", "oauth2-proxy-test-config-XXXX.cfg")
Expect(err).ToNot(HaveOccurred())
defer file.Close()
_, err = file.WriteString(content)
Expect(err).ToNot(HaveOccurred())
return file.Name()
}
It("should pass validation with a valid configuration", func() {
configFile := writeTempConfig(validConfig)
defer os.Remove(configFile)
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
opts, err := loadConfiguration(configFile, "", flagSet, []string{})
Expect(err).ToNot(HaveOccurred())
err = validation.Validate(opts)
Expect(err).ToNot(HaveOccurred())
})
It("should fail validation with an invalid configuration (missing required fields)", func() {
configFile := writeTempConfig(invalidConfig)
defer os.Remove(configFile)
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
opts, err := loadConfiguration(configFile, "", flagSet, []string{})
Expect(err).ToNot(HaveOccurred())
err = validation.Validate(opts)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("invalid configuration"))
})
It("should fail to load a configuration file with syntax errors", func() {
configFile := writeTempConfig("this is not valid toml ===")
defer os.Remove(configFile)
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
_, err := loadConfiguration(configFile, "", flagSet, []string{})
Expect(err).To(HaveOccurred())
})
It("should register the config-test flag", func() {
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
flagSet.ParseErrorsAllowlist.UnknownFlags = true
configTest := flagSet.Bool("config-test", false, "test the configuration and exit")
err := flagSet.Parse([]string{"--config-test"})
Expect(err).ToNot(HaveOccurred())
Expect(*configTest).To(BeTrue())
})
})
})