From ac0d0905ae8617c16e4cdb2fe217b3ac66ff10d5 Mon Sep 17 00:00:00 2001 From: Arun S M Date: Sun, 1 Mar 2026 17:17:34 +0000 Subject: [PATCH] config: treat BufferWindowDays as int and validate range Signed-off-by: S m, Aruna --- cmd/main.go | 5 ++-- internal/pkg/configs/configuration.go | 26 ++++++++++++++++++- internal/pkg/configs/configuration_test.go | 30 ++++++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 internal/pkg/configs/configuration_test.go diff --git a/cmd/main.go b/cmd/main.go index ed02280..cfa4600 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -59,8 +59,9 @@ func main() { log.Printf("current: %v requested: %v", currentTime, requestedTime) log.Printf("difference: %v configured: %v", numberOfDays, config.BufferWindowDays) - // found a case where action is needed - if uint8(numberOfDays) == config.BufferWindowDays { + // found a case where action is needed; both sides are ints now so + // the comparison is straightforward and cannot wrap around. + if numberOfDays == config.BufferWindowDays { // do as scheduled on this date projectInstance := client.GetProject(project) errInfo := projectInstance.CreateIssue(schedule) diff --git a/internal/pkg/configs/configuration.go b/internal/pkg/configs/configuration.go index c054d68..b58e3e2 100644 --- a/internal/pkg/configs/configuration.go +++ b/internal/pkg/configs/configuration.go @@ -1,6 +1,7 @@ package configs import ( + "fmt" "github-issue-schedule/internal/pkg/utils" "io/ioutil" "log" @@ -10,7 +11,12 @@ import ( // Configuration to run the program type Configuration struct { - BufferWindowDays uint8 `yaml:"buffer_window_days"` + // BufferWindowDays indicates how many days in advance a reminder + // issue should be created. Use a signed integer so configs can + // express reasonable values without worrying about overflow when + // comparing against days-calculated-from-the-clock. Negative values + // are invalid and the reader enforces this. + BufferWindowDays int `yaml:"buffer_window_days"` Projects []Project `yaml:"projects"` } @@ -44,5 +50,23 @@ func ReadConfiguration() Configuration { if err != nil { log.Fatalf("Error while parsing the config file %v, Err: %v", configFile, err) } + + if err := config.validate(); err != nil { + log.Fatalf("invalid configuration: %v", err) + } + return config } + +// validate checks that fields in Configuration contain reasonable +// values. callers may use this directly in tests; ReadConfiguration +// itself fatals on any error. +func (c *Configuration) validate() error { + if c.BufferWindowDays < 0 { + return fmt.Errorf("buffer_window_days must be non-negative") + } + if c.BufferWindowDays > 100000 { + return fmt.Errorf("buffer_window_days is unreasonably large (%d)", c.BufferWindowDays) + } + return nil +} diff --git a/internal/pkg/configs/configuration_test.go b/internal/pkg/configs/configuration_test.go new file mode 100644 index 0000000..1598f0f --- /dev/null +++ b/internal/pkg/configs/configuration_test.go @@ -0,0 +1,30 @@ +package configs + +import ( + "testing" +) + +func TestConfigurationValidate(t *testing.T) { + cases := []struct { + desc string + conf Configuration + broken bool + }{ + {"negative", Configuration{BufferWindowDays: -1}, true}, + {"too large", Configuration{BufferWindowDays: 100001}, true}, + {"zero", Configuration{BufferWindowDays: 0}, false}, + {"normal", Configuration{BufferWindowDays: 7}, false}, + } + + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + err := c.conf.validate() + if c.broken && err == nil { + t.Fatalf("expected error for config %+v", c.conf) + } + if !c.broken && err != nil { + t.Fatalf("did not expect error: %v", err) + } + }) + } +}