package config import ( "os" "path/filepath" "strings" "testing" ) func TestWithERPEnvironmentFileUsesApprovedFallbackValues(t *testing.T) { path := writeERPEnvironmentFile(t, strings.Join([]string{ "OTHER_TOOL_TOKEN=ignored", "CMROUBAO_SHUNYUNBAO_URL=https://erp.example.test", "CMROUBAO_SHUNYUNBAO_USERNAME=dotenv-user", "CMROUBAO_SHUNYUNBAO_PASSWORD='dotenv password #1'", }, "\n")) lookup, err := WithERPEnvironmentFile(path, func(string) (string, bool) { return "", false }) if err != nil { t.Fatalf("WithERPEnvironmentFile() error = %v", err) } cfg, err := Load(lookup) if err != nil { t.Fatalf("Load() error = %v", err) } if cfg.ShunyunbaoURL != "https://erp.example.test" || cfg.ShunyunbaoUsername != "dotenv-user" || cfg.ShunyunbaoPassword != "dotenv password #1" { t.Fatalf( "ERP config = %#v", struct { URL string Username string Password string }{cfg.ShunyunbaoURL, cfg.ShunyunbaoUsername, cfg.ShunyunbaoPassword}, ) } if _, exists := lookup("OTHER_TOOL_TOKEN"); exists { t.Fatal("unapproved .env value was exposed") } } func TestWithERPEnvironmentFileProcessEnvironmentTakesPriority(t *testing.T) { path := writeERPEnvironmentFile(t, strings.Join([]string{ "CMROUBAO_SHUNYUNBAO_URL=https://dotenv.example.test", "CMROUBAO_SHUNYUNBAO_USERNAME=dotenv-user", "CMROUBAO_SHUNYUNBAO_PASSWORD=dotenv-password", }, "\n")) process := map[string]string{ ShunyunbaoURLEnvironment: "https://process.example.test", ShunyunbaoUsernameEnvironment: "process-user", ShunyunbaoPasswordEnvironment: "process-password", } lookup, err := WithERPEnvironmentFile(path, lookupMap(process)) if err != nil { t.Fatalf("WithERPEnvironmentFile() error = %v", err) } cfg, err := Load(lookup) if err != nil { t.Fatalf("Load() error = %v", err) } if cfg.ShunyunbaoURL != process[ShunyunbaoURLEnvironment] || cfg.ShunyunbaoUsername != process[ShunyunbaoUsernameEnvironment] || cfg.ShunyunbaoPassword != process[ShunyunbaoPasswordEnvironment] { t.Fatalf("process values did not override .env values") } } func TestWithERPEnvironmentFileAllowsMissingFile(t *testing.T) { lookup, err := WithERPEnvironmentFile( filepath.Join(t.TempDir(), "missing.env"), lookupMap(nil), ) if err != nil { t.Fatalf("WithERPEnvironmentFile() error = %v", err) } if _, exists := lookup(ShunyunbaoUsernameEnvironment); exists { t.Fatal("missing file provided a value") } } func TestWithERPEnvironmentFileRejectsInvalidContentWithoutLeakingValues(t *testing.T) { const secret = "must-not-appear-in-error" testCases := map[string]string{ "invalid name": "not a name=" + secret, "duplicate": strings.Join([]string{ "CMROUBAO_SHUNYUNBAO_USERNAME=" + secret, "CMROUBAO_SHUNYUNBAO_USERNAME=another", }, "\n"), "unknown app config": "CMROUBAO_AUTH_PASSWORD=" + secret, "unmatched quote": "CMROUBAO_SHUNYUNBAO_PASSWORD='" + secret, "nul": "CMROUBAO_SHUNYUNBAO_PASSWORD=" + secret + "\x00", } for name, contents := range testCases { t.Run(name, func(t *testing.T) { path := writeERPEnvironmentFile(t, contents) _, err := WithERPEnvironmentFile(path, lookupMap(nil)) if err == nil { t.Fatal("WithERPEnvironmentFile() error = nil") } if strings.Contains(err.Error(), secret) { t.Fatalf("error leaked .env content: %v", err) } }) } } func TestWithERPEnvironmentFileRejectsOversizedFile(t *testing.T) { path := writeERPEnvironmentFile( t, "CMROUBAO_SHUNYUNBAO_USERNAME="+ strings.Repeat("x", maximumERPEnvironmentFileBytes), ) _, err := WithERPEnvironmentFile(path, lookupMap(nil)) if err == nil { t.Fatal("WithERPEnvironmentFile() error = nil") } } func writeERPEnvironmentFile(t *testing.T, contents string) string { t.Helper() path := filepath.Join(t.TempDir(), ".env") if err := os.WriteFile(path, []byte(contents), 0o600); err != nil { t.Fatalf("os.WriteFile() error = %v", err) } return path } func lookupMap(values map[string]string) LookupEnvironment { return func(name string) (string, bool) { value, exists := values[name] return value, exists } }