Skip to content

Commit

Permalink
fix(encode): ensure quoting is maintained for scalars
Browse files Browse the repository at this point in the history
Currently, when encoding or decoding integers bigger than 64 bytes using
`sigs.k8s.io/yaml/goyaml.v3`, those values are interpreted as unequivocal
strings, which causes quotes to be removed. However, those values should be
treated as regular numbers since they conform to the integer format in the YAML
specification and honour quoting when present in the original input.
  • Loading branch information
stormqueen1990 committed Aug 14, 2024
1 parent c3772b5 commit f404b76
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 1 deletion.
10 changes: 10 additions & 0 deletions goyaml.v3/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"encoding"
"fmt"
"io"
"math/big"
"reflect"
"regexp"
"sort"
Expand Down Expand Up @@ -136,6 +137,9 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
case time.Duration:
e.stringv(tag, reflect.ValueOf(value.String()))
return
case *big.Int:
e.bigintv(tag, reflect.ValueOf(value.String()))
return
case Marshaler:
v, err := value.MarshalYAML()
if err != nil {
Expand Down Expand Up @@ -382,6 +386,12 @@ func (e *encoder) uintv(tag string, in reflect.Value) {
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) bigintv(tag string, in reflect.Value) {
value := &big.Int{}
s, _ := value.SetString(in.String(), 0)
e.emitScalar(s.String(), "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) timev(tag string, in reflect.Value) {
t := in.Interface().(time.Time)
s := t.Format(time.RFC3339Nano)
Expand Down
36 changes: 35 additions & 1 deletion goyaml.v3/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"os"

. "gopkg.in/check.v1"
"sigs.k8s.io/yaml/goyaml.v3"
yaml "sigs.k8s.io/yaml/goyaml.v3"
)

var marshalIntTest = 123
Expand Down Expand Up @@ -731,6 +731,40 @@ func (s *S) TestSortedOutput(c *C) {
}
}

func (s *S) TestQuotingMaintained(c *C) {
var buf bytes.Buffer
var yamlValue map[string]interface{}
const originalYaml = `data:
A1: "0x0000000000000000000000010000000000000000"
A2: "0x000000000000000000000000FFFFFFFFFFFFFFFF"
A3: "1234"
A4: 0x0000000000000000000000010000000000000000
A5: 0x000000000000000000000000FFFFFFFFFFFFFFFF
A6: 1234
`
const outputYaml = `data:
A1: "0x0000000000000000000000010000000000000000"
A2: "0x000000000000000000000000FFFFFFFFFFFFFFFF"
A3: "1234"
A4: 18446744073709551616
A5: 18446744073709551615
A6: 1234
`

dec := yaml.NewDecoder(strings.NewReader(originalYaml))
errDec := dec.Decode(&yamlValue)
c.Assert(errDec, IsNil)

enc := yaml.NewEncoder(&buf)
errEnc := enc.Encode(yamlValue)
c.Assert(errEnc, IsNil)

errClose := enc.Close()
c.Assert(errClose, IsNil)

c.Assert(buf.String(), Equals, outputYaml)
}

func newTime(t time.Time) *time.Time {
return &t
}
13 changes: 13 additions & 0 deletions goyaml.v3/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package yaml

import (
"encoding/base64"
"errors"
"math"
"math/big"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -201,6 +203,17 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
if err == nil {
return intTag, uintv
}

// If integer out of range, check if it's valid for bigger than 64 bytes
if errors.Is(err, strconv.ErrRange) {
value := &big.Int{}

result, ok := value.SetString(plain, 0)
if ok {
return intTag, result
}
}

if yamlStyleFloat.MatchString(plain) {
floatv, err := strconv.ParseFloat(plain, 64)
if err == nil {
Expand Down

0 comments on commit f404b76

Please sign in to comment.