From 7d6923730e34e9005e6a607ccd247d96f7a96bea Mon Sep 17 00:00:00 2001 From: TwiN Date: Sat, 11 Feb 2023 22:43:13 -0500 Subject: [PATCH] fix(config): Support `$$` in config for literal `$` (#427) --- config/config.go | 6 ++++++ config/config_test.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 48bc7a2e..1f2d2051 100644 --- a/config/config.go +++ b/config/config.go @@ -7,6 +7,7 @@ import ( "log" "os" "path/filepath" + "strings" "time" "github.com/TwiN/deepmerge" @@ -214,8 +215,13 @@ func walkConfigDir(path string, fn fs.WalkDirFunc) error { // parseAndValidateConfigBytes parses a Gatus configuration file into a Config struct and validates its parameters func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) { + // Replace $$ with __GATUS_LITERAL_DOLLAR_SIGN__ to prevent os.ExpandEnv from treating "$$" as if it was an + // environment variable. This allows Gatus to support literal "$" in the configuration file. + yamlBytes = []byte(strings.ReplaceAll(string(yamlBytes), "$$", "__GATUS_LITERAL_DOLLAR_SIGN__")) // Expand environment variables yamlBytes = []byte(os.ExpandEnv(string(yamlBytes))) + // Replace __GATUS_LITERAL_DOLLAR_SIGN__ with "$" to restore the literal "$" in the configuration file + yamlBytes = []byte(strings.ReplaceAll(string(yamlBytes), "__GATUS_LITERAL_DOLLAR_SIGN__", "$")) // Parse configuration file if err = yaml.Unmarshal(yamlBytes, &config); err != nil { return diff --git a/config/config_test.go b/config/config_test.go index 1ab465c4..ef1068a7 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1534,7 +1534,34 @@ endpoints: } } -func TestParseAndValidateConfigBytesWithNoEndpointsOrAutoDiscovery(t *testing.T) { +func TestParseAndValidateConfigBytesWithLiteralDollarSign(t *testing.T) { + os.Setenv("GATUS_TestParseAndValidateConfigBytesWithLiteralDollarSign", "whatever") + config, err := parseAndValidateConfigBytes([]byte(` +endpoints: + - name: website + url: https://twin.sh/health + conditions: + - "[BODY] == $$GATUS_TestParseAndValidateConfigBytesWithLiteralDollarSign" + - "[BODY] == $GATUS_TestParseAndValidateConfigBytesWithLiteralDollarSign" +`)) + if err != nil { + t.Error("expected no error, got", err.Error()) + } + if config == nil { + t.Fatal("Config shouldn't have been nil") + } + if config.Endpoints[0].URL != "https://twin.sh/health" { + t.Errorf("URL should have been %s", "https://twin.sh/health") + } + if config.Endpoints[0].Conditions[0] != "[BODY] == $GATUS_TestParseAndValidateConfigBytesWithLiteralDollarSign" { + t.Errorf("Condition should have been %s", "[BODY] == $GATUS_TestParseAndValidateConfigBytesWithLiteralDollarSign") + } + if config.Endpoints[0].Conditions[1] != "[BODY] == whatever" { + t.Errorf("Condition should have been %s", "[BODY] == whatever") + } +} + +func TestParseAndValidateConfigBytesWithNoEndpoints(t *testing.T) { _, err := parseAndValidateConfigBytes([]byte(``)) if err != ErrNoEndpointInConfig { t.Error("The error returned should have been of type ErrNoEndpointInConfig")