Files
dokku/plugins/traefik-vhosts/report_test.go
Jose Diaz-Gonzalez 81a929d768 fix: report traefik dns-provider env vars as global keys
The dynamic `dns-provider-*` properties were reported as `--traefik-dns-provider-<env_var>`, outside the `global`/`computed` namespace every other traefik property uses, so a consumer reading the json report could not tell which of the two a key represented. They are now reported as `--traefik-global-dns-provider-<env_var>`. The `basic-auth-password` property is a credential as well and is now masked in the default report output on the same terms as the dns provider values, meaning the raw value is returned only for `--format json` or when the flag is queried by name.
2026-08-12 03:22:04 -04:00

144 lines
4.7 KiB
Go

package traefikvhosts
import (
"os/user"
"path/filepath"
"testing"
"github.com/dokku/dokku/plugins/common"
)
// setupPropertyEnv points the dokku env at temporary directories and tells the
// permission helpers to chown files to the current user (a no-op) so the test
// works without root.
func setupPropertyEnv(t *testing.T) {
t.Helper()
libRoot := t.TempDir()
t.Setenv("DOKKU_LIB_ROOT", libRoot)
t.Setenv("DOKKU_ROOT", t.TempDir())
t.Setenv("PLUGIN_PATH", filepath.Join(libRoot, "plugins"))
current, err := user.Current()
if err != nil {
t.Fatalf("user.Current: %v", err)
}
group, err := user.LookupGroupId(current.Gid)
if err != nil {
t.Fatalf("user.LookupGroupId: %v", err)
}
t.Setenv("DOKKU_SYSTEM_USER", current.Username)
t.Setenv("DOKKU_SYSTEM_GROUP", group.Name)
}
func staticReportFunc(value string) common.ReportFunc {
return func(string) string {
return value
}
}
func TestMaskedReportFunc(t *testing.T) {
const flagName = "--traefik-global-basic-auth-password"
cases := []struct {
name string
value string
format string
infoFlag string
want string
}{
{name: "stdout masks a set value", value: "hunter2", format: "stdout", want: valueMask},
{name: "empty format masks a set value", value: "hunter2", want: valueMask},
{name: "stdout leaves an unset value empty", value: "", format: "stdout", want: ""},
{name: "json returns the raw value", value: "hunter2", format: "json", want: "hunter2"},
{name: "matching info flag returns the raw value", value: "hunter2", format: "stdout", infoFlag: flagName, want: "hunter2"},
{name: "other info flag masks the value", value: "hunter2", format: "stdout", infoFlag: "--traefik-global-basic-auth-username", want: valueMask},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
fn := maskedReportFunc(staticReportFunc(tc.value), flagName, tc.format, tc.infoFlag)
if got := fn("--global"); got != tc.want {
t.Errorf("maskedReportFunc(%q, %q, %q) = %q, want %q", tc.value, tc.format, tc.infoFlag, got, tc.want)
}
})
}
}
func TestDNSProviderReportFlags(t *testing.T) {
setupPropertyEnv(t)
if err := common.PropertyWrite("traefik", "--global", "dns-provider", "cloudflare"); err != nil {
t.Fatalf("PropertyWrite dns-provider: %v", err)
}
if err := common.PropertyWrite("traefik", "--global", "dns-provider-cf_api_email", "test@example.com"); err != nil {
t.Fatalf("PropertyWrite dns-provider-cf_api_email: %v", err)
}
if err := common.PropertyWrite("traefik", "--global", "dns-provider-cf_api_key", "secret-key"); err != nil {
t.Fatalf("PropertyWrite dns-provider-cf_api_key: %v", err)
}
flags, err := dnsProviderReportFlags("stdout", "")
if err != nil {
t.Fatalf("dnsProviderReportFlags: %v", err)
}
assertReportFuncValue(t, flags, "--traefik-global-dns-provider-cf_api_email", valueMask)
assertReportFuncValue(t, flags, "--traefik-global-dns-provider-cf_api_key", valueMask)
if len(flags) != 2 {
t.Errorf("flags = %v, want only the two dns-provider-* env var flags", flagNames(flags))
}
if _, ok := flags["--traefik-global-dns-provider"]; ok {
t.Error("--traefik-global-dns-provider should be reported statically, not as a dynamic env var")
}
if _, ok := flags["--traefik-dns-provider-cf_api_email"]; ok {
t.Error("--traefik-dns-provider-cf_api_email should not be emitted outside the global namespace")
}
flags, err = dnsProviderReportFlags("json", "")
if err != nil {
t.Fatalf("dnsProviderReportFlags: %v", err)
}
assertReportFuncValue(t, flags, "--traefik-global-dns-provider-cf_api_email", "test@example.com")
assertReportFuncValue(t, flags, "--traefik-global-dns-provider-cf_api_key", "secret-key")
flags, err = dnsProviderReportFlags("stdout", "--traefik-global-dns-provider-cf_api_key")
if err != nil {
t.Fatalf("dnsProviderReportFlags: %v", err)
}
assertReportFuncValue(t, flags, "--traefik-global-dns-provider-cf_api_email", valueMask)
assertReportFuncValue(t, flags, "--traefik-global-dns-provider-cf_api_key", "secret-key")
}
func TestDNSProviderReportFlagsWithoutProperties(t *testing.T) {
setupPropertyEnv(t)
flags, err := dnsProviderReportFlags("stdout", "")
if err != nil {
t.Fatalf("dnsProviderReportFlags: %v", err)
}
if len(flags) != 0 {
t.Errorf("flags = %v, want no flags", flagNames(flags))
}
}
func assertReportFuncValue(t *testing.T, flags map[string]common.ReportFunc, flagName string, want string) {
t.Helper()
fn, ok := flags[flagName]
if !ok {
t.Fatalf("flag %q missing from %v", flagName, flagNames(flags))
}
if got := fn("--global"); got != want {
t.Errorf("flag %q = %q, want %q", flagName, got, want)
}
}
func flagNames(flags map[string]common.ReportFunc) []string {
names := []string{}
for name := range flags {
names = append(names, name)
}
return names
}