feat(config): Strict-YAML, Secret-Dateien, Env-Overrides, Dateirechte und Validierung
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
This commit is contained in:
parent
fbfff90b38
commit
b47ee11ba4
10 changed files with 777 additions and 0 deletions
115
internal/config/validate_test.go
Normal file
115
internal/config/validate_test.go
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func validCfg(t *testing.T) *Config {
|
||||
t.Helper()
|
||||
cfg, err := Parse(strings.NewReader(minimalYAML))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
func TestBaseDNFromDomain(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"firma.local": "DC=firma,DC=local",
|
||||
"ad.firma.example": "DC=ad,DC=firma,DC=example",
|
||||
"FIRMA.LOCAL": "DC=FIRMA,DC=LOCAL",
|
||||
}
|
||||
for in, want := range cases {
|
||||
got, err := BaseDNFromDomain(in)
|
||||
if err != nil {
|
||||
t.Errorf("BaseDNFromDomain(%q): %v", in, err)
|
||||
continue
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("BaseDNFromDomain(%q) = %q, want %q", in, got, want)
|
||||
}
|
||||
}
|
||||
if _, err := BaseDNFromDomain("firmalocal"); err == nil {
|
||||
t.Error("Domain ohne Punkt muss abgelehnt werden")
|
||||
}
|
||||
if _, err := BaseDNFromDomain(""); err == nil {
|
||||
t.Error("leere Domain muss abgelehnt werden")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEffectiveBaseDNPrefersOverride(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.AD.BaseDN = "OU=Users,DC=firma,DC=local"
|
||||
if got := cfg.EffectiveBaseDN(); got != "OU=Users,DC=firma,DC=local" {
|
||||
t.Errorf("Override muss gewinnen, got %q", got)
|
||||
}
|
||||
cfg.AD.BaseDN = ""
|
||||
if got := cfg.EffectiveBaseDN(); got != "DC=firma,DC=local" {
|
||||
t.Errorf("Ableitung falsch, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAcceptsMinimalConfig(t *testing.T) {
|
||||
if err := validCfg(t).Validate(); err != nil {
|
||||
t.Fatalf("minimale Config sollte gültig sein: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsIPServers(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.AD.Servers = []string{"10.1.1.10"}
|
||||
err := cfg.Validate()
|
||||
if err == nil || !strings.Contains(err.Error(), "10.1.1.10") {
|
||||
t.Fatalf("IP-Adresse als DC muss abgelehnt werden, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsHTTPOPNsense(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.OPNsense.URL = "http://fw01.firma.local"
|
||||
if err := cfg.Validate(); err == nil {
|
||||
t.Fatal("http:// muss abgelehnt werden")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsPatternAndRegexTogether(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.Matching.CNRegex = "^.*$"
|
||||
if err := cfg.Validate(); err == nil {
|
||||
t.Fatal("cn_pattern und cn_regex gleichzeitig muss abgelehnt werden")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsBadRegex(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.Matching.CNPattern = ""
|
||||
cfg.Matching.CNRegex = "([unbalanced"
|
||||
if err := cfg.Validate(); err == nil {
|
||||
t.Fatal("unkompilierbare Regex muss abgelehnt werden")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCollectsMultipleErrors(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.Portal.TLSCert = ""
|
||||
cfg.Portal.TLSKey = ""
|
||||
cfg.AD.VPNGroup = ""
|
||||
err := cfg.Validate()
|
||||
if err == nil {
|
||||
t.Fatal("mehrere Fehler erwartet")
|
||||
}
|
||||
for _, want := range []string{"tls_cert", "tls_key", "vpn_group"} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Sammelfehler muss %q nennen, got: %v", want, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsPatternWithoutPlaceholder(t *testing.T) {
|
||||
cfg := validCfg(t)
|
||||
cfg.Matching.CNPattern = "fester-cn"
|
||||
if err := cfg.Validate(); err == nil {
|
||||
t.Fatal("cn_pattern ohne {username} muss abgelehnt werden")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue