Templates: keep large numeric params parseable (#32528)

Co-authored-by: Dennis Klipp <6085348+DennisKlipp@users.noreply.github.com>
This commit is contained in:
Dennis Klipp 2026-08-04 20:29:57 +02:00 • committed by GitHub
parent 124edaa32c
commit dbae128094
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 55 additions and 1 deletions

View file

@ -0,0 +1,38 @@
package templates
import (
"testing"
"github.com/stretchr/testify/assert"
)
// JSON numbers arrive as float64. Large integers must not be rendered in
// exponential notation, which would no longer parse as an integer.
func TestFormatValue(t *testing.T) {
for _, tc := range []struct {
in any
want string
}{
{float64(3), "3"},
{float64(8899), "8899"},
{float64(3493601102), "3493601102"}, // ten digit device serial
{float64(1.5), "1.5"},
{int(42), "42"},
{"text", "text"},
} {
assert.Equal(t, tc.want, formatValue(tc.in))
}
}
// end-to-end: a required int param supplied as a JSON number must satisfy the
// required check, e.g. a ten digit device serial
func TestRequiredLargeNumber(t *testing.T) {
tmpl := &Template{
Params: []Param{{Name: "serial", Type: TypeInt, Required: true}},
}
_, _, err := tmpl.RenderResult(RenderModeUnitTest, map[string]any{
"serial": float64(3493601102),
})
assert.NoError(t, err, "large serial supplied as JSON number")
}

View file

@ -274,6 +274,8 @@ func (t *Template) RenderProxyWithValues(values map[string]any, lang string) ([]
t.Params[index].Value = p.yamlQuote(v)
case int:
t.Params[index].Value = strconv.Itoa(v)
case float64, float32:
t.Params[index].Value = formatValue(v)
}
}
}
@ -308,6 +310,20 @@ func (t *Template) RenderProxyWithValues(values map[string]any, lang string) ([]
return bytes.TrimSpace(out.Bytes()), err
}
// formatValue renders a parameter value for yaml. JSON numbers arrive as float64,
// which %v would render in exponential notation for large values, e.g. a ten digit
// serial number. Those are no longer parseable as integers.
func formatValue(val any) string {
switch v := val.(type) {
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case float32:
return strconv.FormatFloat(float64(v), 'f', -1, 32)
default:
return fmt.Sprintf("%v", val)
}
}
// RenderResult renders the result template to instantiate the proxy
func (t *Template) RenderResult(renderMode int, other map[string]any) ([]byte, map[string]any, error) {
values := t.Defaults(renderMode)
@ -383,7 +399,7 @@ func (t *Template) RenderResult(renderMode int, other map[string]any) ([]byte, m
// prevent rendering nil interfaces as "<nil>" string
var s string
if val != nil {
s = p.yamlQuote(fmt.Sprintf("%v", val))
s = p.yamlQuote(formatValue(val))
}
// validate required fields from yaml