Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions functional-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,57 @@ bar: baz
}
}

#[test]
fn test_ini_values_as_strings() {
let file_path = prepare_temp_file(
"test_ini_values_as_strings.yaml",
b"the_section:
int: 123
float: 1.23
bool: true
date: 2025-01-02
timestamp: 2025-01-02 03:04:05
utc_timestamp: 2025-01-02T03:04:05Z
string: this is a string",
);
assert!(
Command::new(SOPS_BINARY_PATH)
.arg("encrypt")
.arg("-i")
.arg(file_path.clone())
.output()
.expect("Error running sops")
.status
.success(),
"sops didn't exit successfully"
);
let output = Command::new(SOPS_BINARY_PATH)
.arg("decrypt")
.arg("--output-type")
.arg("ini")
.arg(file_path.clone())
.output()
.expect("Error running sops");
println!(
"stdout: {}, stderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
assert!(output.status.success(), "sops didn't exit successfully");
let data = &String::from_utf8_lossy(&output.stdout);
assert!(
data == "[the_section]
int = 123
float = 1.23
bool = true
date = 2025-01-02T00:00:00Z
timestamp = 2025-01-02T03:04:05Z
utc_timestamp = 2025-01-02T03:04:05Z
string = this is a string
"
);
}

#[test]
fn encrypt_yaml_file() {
let file_path = prepare_temp_file(
Expand Down
17 changes: 1 addition & 16 deletions stores/ini/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"bytes"
"encoding/json"
"fmt"

"strconv"
"strings"

"github.com/getsops/sops/v3"
Expand Down Expand Up @@ -56,7 +54,7 @@ func (store Store) encodeTree(branches sops.TreeBranches) ([]byte, error) {
lastItem.Comment = comment.Value
}
} else {
lastItem, err = section.NewKey(keyVal.Key.(string), store.valToString(keyVal.Value))
lastItem, err = section.NewKey(keyVal.Key.(string), stores.ValToString(keyVal.Value))
if err != nil {
return nil, fmt.Errorf("Error encoding key: %s", err)
}
Expand All @@ -78,19 +76,6 @@ func (store Store) stripCommentChar(comment string) string {
return comment
}

func (store Store) valToString(v interface{}) string {
switch v := v.(type) {
case fmt.Stringer:
return v.String()
case float64:
return strconv.FormatFloat(v, 'f', 6, 64)
case bool:
return strconv.FormatBool(v)
default:
return fmt.Sprintf("%s", v)
}
}

func (store Store) iniFromTreeBranches(branches sops.TreeBranches) ([]byte, error) {
return store.encodeTree(branches)
}
Expand Down
27 changes: 25 additions & 2 deletions stores/stores.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ of the purpose of this package is to make it easy to change the SOPS file format
package stores

import (
"time"

"fmt"
"strconv"
"strings"
"time"

"github.com/getsops/sops/v3"
"github.com/getsops/sops/v3/age"
Expand Down Expand Up @@ -533,3 +534,25 @@ func HasSopsTopLevelKey(branch sops.TreeBranch) bool {
}
return false
}

// ValToString converts a simple value to a string.
// It does not handle complex values (arrays and mappings).
func ValToString(v interface{}) string {
switch v := v.(type) {
case float64:
result := strconv.FormatFloat(v, 'G', -1, 64)
// If the result can be confused with an integer, make sure we have at least one decimal digit
if !strings.ContainsRune(result, '.') && !strings.ContainsRune(result, 'E') {
result = strconv.FormatFloat(v, 'f', 1, 64)
}
return result
case bool:
return strconv.FormatBool(v)
case time.Time:
return v.Format(time.RFC3339)
case fmt.Stringer:
return v.String()
default:
return fmt.Sprintf("%v", v)
}
}
27 changes: 27 additions & 0 deletions stores/stores_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package stores

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)


func TestValToString(t *testing.T) {
assert.Equal(t, "1", ValToString(1))
assert.Equal(t, "1.0", ValToString(1.0))
assert.Equal(t, "1.1", ValToString(1.10))
assert.Equal(t, "1.23", ValToString(1.23))
assert.Equal(t, "1.2345678901234567", ValToString(1.234567890123456789))
assert.Equal(t, "200000.0", ValToString(2E5))
assert.Equal(t, "-2E+10", ValToString(-2E10))
assert.Equal(t, "2E-10", ValToString(2E-10))
assert.Equal(t, "1.2345E+100", ValToString(1.2345E100))
assert.Equal(t, "1.2345E-100", ValToString(1.2345E-100))
assert.Equal(t, "true", ValToString(true))
assert.Equal(t, "false", ValToString(false))
ts, _ := time.Parse(time.RFC3339, "2025-01-02T03:04:05Z")
assert.Equal(t, "2025-01-02T03:04:05Z", ValToString(ts))
assert.Equal(t, "a string", ValToString("a string"))
}
Loading