From a093c103076b34f6c8c849654666ce4cc434382a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:28:20 +0000 Subject: [PATCH 1/3] fix: prevent integer truncation in stableHash (go/incorrect-integer-conversion) Fixes CodeQL alert #637 (high severity). The stableHash function was converting the architecture-dependent int parameter 'modulo' to uint32 before performing the modulo operation. On 64-bit platforms where int is 64 bits wide, values exceeding math.MaxUint32 (~4.3 billion) would be silently truncated, producing an incorrect hash bucket. Replace the uint32(modulo) cast with int64 arithmetic to keep full precision: return int(int64(h.Sum32()) % int64(modulo)) Also add a modulo <= 0 guard to prevent a divide-by-zero panic if a caller ever passes a non-positive modulus. CWE-681: Incorrect Conversion between Numeric Types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/parser/schedule_fuzzy_scatter.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/parser/schedule_fuzzy_scatter.go b/pkg/parser/schedule_fuzzy_scatter.go index 14080e3e916..e443bbd3c3c 100644 --- a/pkg/parser/schedule_fuzzy_scatter.go +++ b/pkg/parser/schedule_fuzzy_scatter.go @@ -176,7 +176,12 @@ func stableHash(s string, modulo int) int { scheduleFuzzyScatterLog.Printf("Warning: hash write failed: %v", err) return 0 } - return int(h.Sum32() % uint32(modulo)) + if modulo <= 0 { + return 0 + } + // Use int64 arithmetic to avoid truncation when modulo exceeds math.MaxUint32 + // on 64-bit platforms where int is 64 bits wide. + return int(int64(h.Sum32()) % int64(modulo)) } // ScatterSchedule takes a fuzzy cron expression and a workflow identifier From c4c4c57ea9a39a0018199ec4a97f3313d26531ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:58:42 +0000 Subject: [PATCH 2/3] docs: clarify stableHash contract for non-positive modulo values Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/parser/schedule_fuzzy_scatter.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/parser/schedule_fuzzy_scatter.go b/pkg/parser/schedule_fuzzy_scatter.go index e443bbd3c3c..9bdd2ccc396 100644 --- a/pkg/parser/schedule_fuzzy_scatter.go +++ b/pkg/parser/schedule_fuzzy_scatter.go @@ -168,6 +168,7 @@ func avoidPeakMinutes(hour, minute int) int { // stableHash returns a deterministic hash value in the range [0, modulo) // using FNV-1a hash algorithm, which is stable across platforms and Go versions. +// If modulo is <= 0, stableHash returns 0 (the range is empty/invalid). func stableHash(s string, modulo int) int { h := fnv.New32a() // hash.Hash.Write never returns an error in practice, but check to satisfy gosec G104 From cf952da0d79a726b500fe7db9cfd4c4f01628002 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 12:01:26 +0000 Subject: [PATCH 3/3] fix: add regression tests and warning log for stableHash edge cases Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/parser/schedule_fuzzy_scatter.go | 1 + pkg/parser/schedule_fuzzy_scatter_test.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/pkg/parser/schedule_fuzzy_scatter.go b/pkg/parser/schedule_fuzzy_scatter.go index 9bdd2ccc396..6471ee1473e 100644 --- a/pkg/parser/schedule_fuzzy_scatter.go +++ b/pkg/parser/schedule_fuzzy_scatter.go @@ -178,6 +178,7 @@ func stableHash(s string, modulo int) int { return 0 } if modulo <= 0 { + scheduleFuzzyScatterLog.Printf("Warning: stableHash called with non-positive modulo %d, returning 0", modulo) return 0 } // Use int64 arithmetic to avoid truncation when modulo exceeds math.MaxUint32 diff --git a/pkg/parser/schedule_fuzzy_scatter_test.go b/pkg/parser/schedule_fuzzy_scatter_test.go index 73fd341ce25..10055c49325 100644 --- a/pkg/parser/schedule_fuzzy_scatter_test.go +++ b/pkg/parser/schedule_fuzzy_scatter_test.go @@ -4,6 +4,7 @@ package parser import ( "fmt" + "math" "strings" "testing" ) @@ -557,6 +558,23 @@ func TestStableHash(t *testing.T) { if hash1 == hash3 { t.Logf("Warning: different strings produced same hash (rare but possible)") } + + // Test zero modulo returns 0 (guard against divide-by-zero) + if got := stableHash("any", 0); got != 0 { + t.Errorf("stableHash(_, 0) = %d, want 0", got) + } + + // Test negative modulo returns 0 safely + if got := stableHash("any", -1); got != 0 { + t.Errorf("stableHash(_, -1) = %d, want 0", got) + } + + // Test modulo larger than math.MaxUint32 to guard against truncation regression + const largeModulo = math.MaxUint32 + 1 // 4_294_967_296 + hashLarge := stableHash("test-workflow", largeModulo) + if hashLarge < 0 || hashLarge >= largeModulo { + t.Errorf("stableHash out of range for large modulo: got %d, want [0, %d)", hashLarge, largeModulo) + } } func TestScatterScheduleWeekdays(t *testing.T) {