diff --git a/pkg/workflow/compilerenv/manager.go b/pkg/workflow/compilerenv/manager.go index a349fb86a11..e63b8a359d4 100644 --- a/pkg/workflow/compilerenv/manager.go +++ b/pkg/workflow/compilerenv/manager.go @@ -53,7 +53,7 @@ const ( // otherwise returns the parsed override as a string. func ResolveDefaultMaxTurns(fallback string) string { if parsed, ok := parsePositiveIntEnvVar(DefaultMaxTurns); ok { - return strconv.FormatInt(parsed, 10) + return strconv.Itoa(parsed) } return fallback } @@ -62,7 +62,7 @@ func ResolveDefaultMaxTurns(fallback string) string { // otherwise returns the parsed override. func ResolveDefaultTimeoutMinutes(fallback int) int { if parsed, ok := parsePositiveIntEnvVar(DefaultTimeoutMinutes); ok { - return int(parsed) + return parsed } return fallback } @@ -71,7 +71,7 @@ func ResolveDefaultTimeoutMinutes(fallback int) int { // otherwise returns the parsed override. func ResolveDefaultMaxTurnCacheMisses(fallback int) int { if parsed, ok := parsePositiveIntEnvVar(DefaultMaxTurnCacheMisses); ok { - return int(parsed) + return parsed } return fallback } @@ -98,15 +98,15 @@ func ResolveDefaultUTC(fallback string) string { return raw } -// parsePositiveIntEnvVar parses an environment variable as a base-10 positive int64. +// parsePositiveIntEnvVar parses an environment variable as a base-10 positive int. // It returns (value, true) when the variable is set to a valid value > 0. // For unset, empty, non-numeric, or non-positive values, it returns (0, false). -func parsePositiveIntEnvVar(name string) (int64, bool) { +func parsePositiveIntEnvVar(name string) (int, bool) { raw := strings.TrimSpace(os.Getenv(name)) if raw == "" { return 0, false } - parsed, err := strconv.ParseInt(raw, 10, 64) + parsed, err := strconv.Atoi(raw) if err != nil || parsed <= 0 { return 0, false } diff --git a/pkg/workflow/compilerenv/manager_test.go b/pkg/workflow/compilerenv/manager_test.go index 75cbeb503f5..cea6733c18b 100644 --- a/pkg/workflow/compilerenv/manager_test.go +++ b/pkg/workflow/compilerenv/manager_test.go @@ -1,6 +1,7 @@ package compilerenv import ( + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -106,6 +107,21 @@ func TestResolveDefaultMaxTurnCacheMisses(t *testing.T) { }) } +func TestParsePositiveIntEnvVar_OverflowRegression(t *testing.T) { + // 2^31 = 2147483648, one above MaxInt32 (2^31-1): fits in int64 but overflows int32. + // On 32-bit platforms (strconv.IntSize == 32) strconv.Atoi rejects this + // value, so the function must fall back to the default — the original + // CWE-190 silent-overflow scenario. On 64-bit platforms it parses + // successfully, proving no over-restriction. + const bigVal = "2147483648" + t.Setenv(DefaultTimeoutMinutes, bigVal) + if strconv.IntSize == 32 { + assert.Equal(t, 20, ResolveDefaultTimeoutMinutes(20), "overflow value must fall back on 32-bit") + } else { + assert.Equal(t, 2147483648, ResolveDefaultTimeoutMinutes(20), "value fits on 64-bit, must parse") + } +} + func TestResolveDefaultDetectionModel(t *testing.T) { t.Run("unset uses fallback", func(t *testing.T) { t.Setenv(DefaultDetectionModel, "")