Skip to content

Commit 585ffd8

Browse files
committed
Auto-detect dotenv format on load
Signed-off-by: Ilia Choly <ilia.choly@gmail.com>
1 parent 8e4f304 commit 585ffd8

3 files changed

Lines changed: 40 additions & 3 deletions

File tree

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,7 @@ The store configuration object can have the following keys:
21022102
* ``dotenv``: this is an object, supporting the following keys:
21032103
21042104
* ``quote`` (boolean; default ``false``): when ``true``, values are
2105-
double-quoted on emit and must be double-quoted on load.
2105+
double-quoted on emit.
21062106
21072107
* ``ini``: this is an object. Right now no keys are supported.
21082108

stores/dotenv/store.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,27 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
8383
// LoadPlainFile returns the contents of a plaintext file loaded onto a
8484
// sops runtime object
8585
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
86+
lines := bytes.Split(in, []byte("\n"))
87+
88+
// Detect the dialect from the first sops_* line: leading '"' means
89+
// quoted, otherwise unquoted.
90+
quote := store.config.Quote
91+
for _, line := range lines {
92+
if !bytes.HasPrefix(line, []byte(SopsPrefix)) {
93+
continue
94+
}
95+
_, raw, ok := bytes.Cut(line, []byte("="))
96+
if !ok {
97+
continue
98+
}
99+
quote = bytes.HasPrefix(raw, []byte(`"`))
100+
break
101+
}
102+
86103
var branches sops.TreeBranches
87104
var branch sops.TreeBranch
88105

89-
for _, line := range bytes.Split(in, []byte("\n")) {
106+
for _, line := range lines {
90107
if len(line) == 0 {
91108
continue
92109
}
@@ -101,7 +118,7 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
101118
return nil, fmt.Errorf("invalid dotenv input line: %s", line)
102119
}
103120
var value string
104-
if store.config.Quote {
121+
if quote {
105122
var err error
106123
value, err = strconv.Unquote(string(line[pos+1:]))
107124
if err != nil {

stores/dotenv/store_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,26 @@ func TestQuotedEmitPlainFile(t *testing.T) {
140140
assert.Equal(t, QUOTED_PLAIN, bytes)
141141
}
142142

143+
func TestQuotedLoadDetectsUnquoted(t *testing.T) {
144+
unquoted, err := (&Store{}).EmitEncryptedFile(sops.Tree{
145+
Branches: sops.TreeBranches{BRANCH},
146+
})
147+
assert.Nil(t, err)
148+
branches, err := (&Store{config: config.DotenvStoreConfig{Quote: true}}).LoadPlainFile(unquoted)
149+
assert.Nil(t, err)
150+
assert.Equal(t, BRANCH, branches[0][:len(BRANCH)])
151+
}
152+
153+
func TestUnquotedLoadDetectsQuoted(t *testing.T) {
154+
quoted, err := (&Store{config: config.DotenvStoreConfig{Quote: true}}).EmitEncryptedFile(sops.Tree{
155+
Branches: sops.TreeBranches{BRANCH},
156+
})
157+
assert.Nil(t, err)
158+
branches, err := (&Store{}).LoadPlainFile(quoted)
159+
assert.Nil(t, err)
160+
assert.Equal(t, BRANCH, branches[0][:len(BRANCH)])
161+
}
162+
143163
func TestHasSopsTopLevelKey(t *testing.T) {
144164
ok := (&Store{}).HasSopsTopLevelKey(sops.TreeBranch{
145165
sops.TreeItem{

0 commit comments

Comments
 (0)