From f9dffa6c29d95cbc5ed2989b8eb0c92134ed7de6 Mon Sep 17 00:00:00 2001 From: Dario Tranchitella Date: Mon, 23 Sep 2024 17:28:21 +0200 Subject: [PATCH] BUG/MINOR: version: sanitizing user input --- config-parser/parsers/extra/config-version.go | 5 +++ configuration/raw.go | 25 ++++++++++++++- test/version_test.go | 31 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/config-parser/parsers/extra/config-version.go b/config-parser/parsers/extra/config-version.go index 4973ce3f..10b8caa2 100644 --- a/config-parser/parsers/extra/config-version.go +++ b/config-parser/parsers/extra/config-version.go @@ -57,6 +57,11 @@ func (p *ConfigVersion) Parse(line string, parts []string, comment string) (stri if len(data) < 2 { return "", &errors.ParseError{Parser: "ConfigVersion", Line: line} } + + if p.data != nil { + return "", &errors.ParseError{Parser: "ConfigVersion", Line: line} + } + if version, err := strconv.ParseInt(data[1], 10, 64); err == nil { p.data = &types.ConfigVersion{ Value: version, diff --git a/configuration/raw.go b/configuration/raw.go index 1a6c8350..14d214b2 100644 --- a/configuration/raw.go +++ b/configuration/raw.go @@ -180,7 +180,7 @@ func (c *client) PostRawConfiguration(config *string, version int64, skipVersion w := bufio.NewWriter(tmp) if !skipVersionCheck { - _, _ = w.WriteString(fmt.Sprintf("# _version=%v\n%v", version, *config)) + _, _ = w.WriteString(fmt.Sprintf("# _version=%v\n%v", version, c.dropVersionFromRaw(*config))) } else { _, _ = w.WriteString(*config) } @@ -204,6 +204,29 @@ func (c *client) PostRawConfiguration(config *string, version int64, skipVersion return nil } +// dropVersionFromRaw is used when force pushing a raw configuration with version check: +// if the provided user input has already a version metadata it must be withdrawn. +func (c *client) dropVersionFromRaw(input string) *string { + scanner := bufio.NewScanner(strings.NewReader(input)) + + var sanitized strings.Builder + + for scanner.Scan() { + t := scanner.Bytes() + + if bytes.HasPrefix(t, []byte("# _version=")) { + continue + } + + sanitized.Write(t) + sanitized.WriteByte('\n') + } + + str := sanitized.String() + + return &str +} + func (c *client) validateConfigFile(confFile string) error { // #nosec G204 cmd := exec.Command(c.Haproxy) diff --git a/test/version_test.go b/test/version_test.go index 05bf1e41..0701baf4 100644 --- a/test/version_test.go +++ b/test/version_test.go @@ -18,6 +18,9 @@ package test import ( "io/ioutil" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func generateConfig(config string) (string, error) { @@ -32,6 +35,34 @@ func generateConfig(config string) (string, error) { return f.Name(), nil } +func TestClient_PostRawConfiguration(t *testing.T) { + fVersion, err := generateConfig("") + require.NoError(t, err, "generateConfig") + + t.Cleanup(func() { + assert.NoError(t, deleteTestFile(fVersion), "clean-up") + }) + + c, err := prepareClient(fVersion) + require.NoError(t, err, "prepareClient") + + v, vErr := c.GetVersion("") + assert.Equal(t, int64(1), v, "initialized configuration must be 1") + // The user is providing a raw configuration with a wrong version such as metadata: + // this must be ignored and removed by Client Native + configWithVersion := `# _version=123 +global + daemon` + + err = c.PostRawConfiguration(&configWithVersion, 1, false) + require.NoError(t, err, "PostRawConfiguration") + + v, vErr = c.GetVersion("") + require.NoError(t, vErr, "GetVersion") + + assert.Equal(t, int64(2), v, "123 should be dropped, and version bumped") +} + func TestClient_GetConfigurationVersion(t *testing.T) { configWithVersion := `# _version=10 global