From dd0551fee72f89cc80f2eedcb8f6c20c28d77eea Mon Sep 17 00:00:00 2001 From: gOOvER Date: Tue, 5 May 2026 13:24:58 +0200 Subject: [PATCH 1/4] fix: preserve boolean/numeric types when panel expands template variables --- parser/helpers.go | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/parser/helpers.go b/parser/helpers.go index a7758034..906317e8 100644 --- a/parser/helpers.go +++ b/parser/helpers.go @@ -38,7 +38,11 @@ var xmlValueMatchRegex = regexp.MustCompile(`^\[([\w]+)='(.*)'\]$`) // Gets the value of a key based on the value type defined. func (cfr *ConfigurationFileReplacement) getKeyValue(value string) interface{} { if cfr.ReplaceWith.Type() == jsonparser.Boolean { - v, _ := strconv.ParseBool(value) + v, err := strconv.ParseBool(value) + if err != nil { + log.WithField("value", value).Warn("cannot parse replacement as boolean, falling back to string value") + return value + } return v } @@ -173,12 +177,38 @@ func (cfr *ConfigurationFileReplacement) setValueWithSjson(jsonStr string, path var setValue interface{} if cfr.ReplaceWith.Type() == jsonparser.Boolean { - v, _ := strconv.ParseBool(value) - setValue = v - } else if v, err := strconv.Atoi(value); err == nil { + // Explicit boolean type declared in the egg definition. + v, err := strconv.ParseBool(value) + if err != nil { + log.WithField("value", value).Warn("cannot parse replacement as boolean, falling back to string value") + return sjson.Set(jsonStr, path, value) + } setValue = v } else { - setValue = value + // Mirror the type already present in the document so booleans and numbers + // survive template expansion (panel always sends values as JSON strings). + existing := gjson.Get(jsonStr, path) + switch existing.Type { + case gjson.True, gjson.False: + v, err := strconv.ParseBool(value) + if err != nil { + log.WithField("value", value).Warn("cannot parse replacement as boolean, falling back to string value") + return sjson.Set(jsonStr, path, value) + } + setValue = v + case gjson.Number: + if v, err := strconv.ParseFloat(value, 64); err == nil { + setValue = v + } else { + setValue = value + } + default: + if v, err := strconv.Atoi(value); err == nil { + setValue = v + } else { + setValue = value + } + } } return sjson.Set(jsonStr, path, setValue) From 1731963baec28e875d30bf89b2ac7d0f67658b6e Mon Sep 17 00:00:00 2001 From: gOOvER Date: Tue, 5 May 2026 13:58:31 +0200 Subject: [PATCH 2/4] fix: use SetRaw for numbers to avoid float64 precision loss --- parser/helpers.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/parser/helpers.go b/parser/helpers.go index 906317e8..e42594da 100644 --- a/parser/helpers.go +++ b/parser/helpers.go @@ -197,11 +197,13 @@ func (cfr *ConfigurationFileReplacement) setValueWithSjson(jsonStr string, path } setValue = v case gjson.Number: - if v, err := strconv.ParseFloat(value, 64); err == nil { - setValue = v - } else { - setValue = value + // Write the numeric literal as-is via SetRaw to avoid float64 precision + // loss for large integers (> 2^53). Fall back to string if the incoming + // value is not a valid JSON number. + if gjson.Parse(value).Type == gjson.Number { + return sjson.SetRaw(jsonStr, path, value) } + setValue = value default: if v, err := strconv.Atoi(value); err == nil { setValue = v From 14fe4a535c7eeafbec6ac04705a2b99168177866 Mon Sep 17 00:00:00 2001 From: gOOvER Date: Tue, 5 May 2026 13:59:36 +0200 Subject: [PATCH 3/4] fix: add path and match context to boolean parse warning logs --- parser/helpers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parser/helpers.go b/parser/helpers.go index e42594da..c608457c 100644 --- a/parser/helpers.go +++ b/parser/helpers.go @@ -40,7 +40,7 @@ func (cfr *ConfigurationFileReplacement) getKeyValue(value string) interface{} { if cfr.ReplaceWith.Type() == jsonparser.Boolean { v, err := strconv.ParseBool(value) if err != nil { - log.WithField("value", value).Warn("cannot parse replacement as boolean, falling back to string value") + log.WithFields(log.Fields{"value": value, "match": cfr.Match}).Warn("cannot parse replacement as boolean, falling back to string value") return value } return v @@ -180,7 +180,7 @@ func (cfr *ConfigurationFileReplacement) setValueWithSjson(jsonStr string, path // Explicit boolean type declared in the egg definition. v, err := strconv.ParseBool(value) if err != nil { - log.WithField("value", value).Warn("cannot parse replacement as boolean, falling back to string value") + log.WithFields(log.Fields{"value": value, "path": path, "match": cfr.Match}).Warn("cannot parse replacement as boolean, falling back to string value") return sjson.Set(jsonStr, path, value) } setValue = v @@ -192,7 +192,7 @@ func (cfr *ConfigurationFileReplacement) setValueWithSjson(jsonStr string, path case gjson.True, gjson.False: v, err := strconv.ParseBool(value) if err != nil { - log.WithField("value", value).Warn("cannot parse replacement as boolean, falling back to string value") + log.WithFields(log.Fields{"value": value, "path": path, "match": cfr.Match}).Warn("cannot parse replacement as boolean, falling back to string value") return sjson.Set(jsonStr, path, value) } setValue = v From e9a08279d977d336588d328744d18b22a88eaabc Mon Sep 17 00:00:00 2001 From: gOOvER Date: Tue, 5 May 2026 14:00:24 +0200 Subject: [PATCH 4/4] fix: remove unused getKeyValue (dead code) --- parser/helpers.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/parser/helpers.go b/parser/helpers.go index c608457c..e34013b1 100644 --- a/parser/helpers.go +++ b/parser/helpers.go @@ -35,26 +35,6 @@ var configMatchRegex = regexp.MustCompile(`{{\s?config\.([\w.-]+)\s?}}`) // noinspection RegExpRedundantEscape var xmlValueMatchRegex = regexp.MustCompile(`^\[([\w]+)='(.*)'\]$`) -// Gets the value of a key based on the value type defined. -func (cfr *ConfigurationFileReplacement) getKeyValue(value string) interface{} { - if cfr.ReplaceWith.Type() == jsonparser.Boolean { - v, err := strconv.ParseBool(value) - if err != nil { - log.WithFields(log.Fields{"value": value, "match": cfr.Match}).Warn("cannot parse replacement as boolean, falling back to string value") - return value - } - return v - } - - // Try to parse into an int, if this fails just ignore the error and continue - // through, returning the string. - if v, err := strconv.Atoi(value); err == nil { - return v - } - - return value -} - // Iterate over an unstructured JSON/YAML/etc. interface and set all of the required // key/value pairs for the configuration file. //