From 3ad5e74c68028b237ecb1679ba37a83548eb9c21 Mon Sep 17 00:00:00 2001 From: Midas Lambrichts Date: Tue, 4 Feb 2025 19:57:16 +0100 Subject: [PATCH] Add (simple) support for quoted multiline variables in .env files Signed-off-by: Midas Lambrichts --- stores/dotenv/store.go | 37 +++++++++++++++++++++++++++++++++++-- stores/dotenv/store_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/stores/dotenv/store.go b/stores/dotenv/store.go index 1e533341e..40f13e308 100644 --- a/stores/dotenv/store.go +++ b/stores/dotenv/store.go @@ -3,6 +3,7 @@ package dotenv //import "github.com/getsops/sops/v3/stores/dotenv" import ( "bytes" "fmt" + "slices" "sort" "strings" @@ -76,7 +77,32 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) { var branches sops.TreeBranches var branch sops.TreeBranch - for _, line := range bytes.Split(in, []byte("\n")) { + var lines [][]byte + var inQuotes = false + var currentQuoteChar byte = '"' + var lastSplit = -1 + + for pos, char := range in { + switch char { + case '"', '\'', '`': + if inQuotes { + if currentQuoteChar == char { + inQuotes = false + } + } else { + inQuotes = true + currentQuoteChar = char + } + case '\n': + if !inQuotes { + var line = in[lastSplit+1 : pos] + lines = append(lines, line) + lastSplit = pos + } + } + } + + for _, line := range lines { if len(line) == 0 { continue } @@ -141,8 +167,15 @@ func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) { if comment, ok := item.Key.(sops.Comment); ok { line = fmt.Sprintf("#%s\n", comment.Value) } else { - value := strings.Replace(item.Value.(string), "\n", "\\n", -1) + stringValue := item.Value.(string) + var value string + if len(stringValue) == 0 || !slices.Contains([]byte{'"', '\'', '`'}, stringValue[0]) { + value = strings.Replace(stringValue, "\n", "\\n", -1) + } else { + value = item.Value.(string) + } line = fmt.Sprintf("%s=%s\n", item.Key, value) + } buffer.WriteString(line) } diff --git a/stores/dotenv/store_test.go b/stores/dotenv/store_test.go index 6886fbc34..25e17e3b9 100644 --- a/stores/dotenv/store_test.go +++ b/stores/dotenv/store_test.go @@ -14,6 +14,15 @@ VAR2=val2 #comment VAR3_unencrypted=val3 VAR4=val4\nval4 +VAR5="val5quoted" +VAR6="val6 +quoted +multiline" +VAR7='val7 +multiline' +VAR8='val8" +mixing +"quotes' `, "\n")) var BRANCH = sops.TreeBranch{ @@ -37,6 +46,22 @@ var BRANCH = sops.TreeBranch{ Key: "VAR4", Value: "val4\nval4", }, + sops.TreeItem{ + Key: "VAR5", + Value: "\"val5quoted\"", + }, + sops.TreeItem{ + Key: "VAR6", + Value: "\"val6\nquoted\nmultiline\"", + }, + sops.TreeItem{ + Key: "VAR7", + Value: "'val7\nmultiline'", + }, + sops.TreeItem{ + Key: "VAR8", + Value: "'val8\"\nmixing\n\"quotes'", + }, } func TestLoadPlainFile(t *testing.T) {