fix(app): keep signed numeric env values unchanged (#14180)

This commit is contained in:
Raphael Fakhri
2026-10-27 09:58:53 +08:00
committed by GitHub
parent 19707a68dd
commit ac09426f10
2 changed files with 51 additions and 6 deletions
+9 -6
View File
@@ -29,7 +29,7 @@ func Write(envMap map[string]string, filename string) error {
func Marshal(envMap map[string]string) (string, error) {
lines := make([]string, 0, len(envMap))
for k, v := range envMap {
if d, err := strconv.Atoi(v); err == nil && !isStartWithZero(v) {
if d, ok := canonicalInt(v); ok {
lines = append(lines, fmt.Sprintf(`%s=%d`, k, d))
} else if shouldUseSingleQuotes(v) {
lines = append(lines, fmt.Sprintf(`%s='%s'`, k, v))
@@ -86,7 +86,7 @@ func MarshalWithOrder(envMap map[string]string, orders []string) (string, error)
}
func formatEnvLine(k, v string) string {
if d, err := strconv.Atoi(v); err == nil && !isStartWithZero(v) {
if d, ok := canonicalInt(v); ok {
return fmt.Sprintf(`%s=%d`, k, d)
} else if shouldUseSingleQuotes(v) {
return fmt.Sprintf(`%s='%s'`, k, v)
@@ -107,11 +107,14 @@ func GetEnvValueByKey(envPath, key string) (string, error) {
return value, nil
}
func isStartWithZero(value string) bool {
if strings.HasPrefix(value, "0") && len(value) > 1 {
return true
// canonicalInt reports whether value is an integer that formats back to the
// same string, so values such as "007", "+1" or "-01" keep their exact text.
func canonicalInt(value string) (int, bool) {
d, err := strconv.Atoi(value)
if err != nil || strconv.Itoa(d) != value {
return 0, false
}
return false
return d, true
}
func hasEvenDoubleQuotes(s string) bool {
+42
View File
@@ -0,0 +1,42 @@
package env
import (
"testing"
"github.com/joho/godotenv"
)
func TestMarshalKeepsValuesExactly(t *testing.T) {
values := []string{"3306", "0", "-1", "007", "+123456", "-0123", "+0", "-0", "a'b", `a"b`, `a\b`}
for _, v := range values {
envMap := map[string]string{"PANEL_DB_ROOT_PASSWORD": v}
for name, marshal := range map[string]func(map[string]string) (string, error){
"Marshal": Marshal,
"MarshalWithOrder": func(m map[string]string) (string, error) {
return MarshalWithOrder(m, []string{"PANEL_DB_ROOT_PASSWORD"})
},
} {
content, err := marshal(envMap)
if err != nil {
t.Fatalf("%s(%q) returned error: %v", name, v, err)
}
parsed, err := godotenv.Unmarshal(content)
if err != nil {
t.Fatalf("%s(%q) produced unparsable content %q: %v", name, v, content, err)
}
if got := parsed["PANEL_DB_ROOT_PASSWORD"]; got != v {
t.Errorf("%s(%q) wrote %q, which reads back as %q", name, v, content, got)
}
}
}
}
func TestMarshalWritesCanonicalIntegersUnquoted(t *testing.T) {
content, err := Marshal(map[string]string{"PANEL_APP_PORT_HTTP": "8080"})
if err != nil {
t.Fatal(err)
}
if content != "PANEL_APP_PORT_HTTP=8080" {
t.Fatalf("Marshal() = %q, want %q", content, "PANEL_APP_PORT_HTTP=8080")
}
}