diff --git a/changelog/_9942.txt b/changelog/_9942.txt new file mode 100644 index 0000000000..c25eaa1c4c --- /dev/null +++ b/changelog/_9942.txt @@ -0,0 +1,3 @@ +```release-note:bug +core: interpret all new rotation manager rotation_schedules as UTC to avoid inadvertent use of tz-local +``` diff --git a/sdk/rotation/schedule.go b/sdk/rotation/schedule.go index 8d4af151f7..b1a5b8f105 100644 --- a/sdk/rotation/schedule.go +++ b/sdk/rotation/schedule.go @@ -52,6 +52,10 @@ func (d *DefaultSchedule) Parse(rotationSchedule string) (*cron.SpecSchedule, er if !ok { return nil, fmt.Errorf("invalid rotation schedule") } + + // override the timezone in all cases, even if was set otherwise + sched.Location = time.UTC + return sched, nil } diff --git a/sdk/rotation/schedule_test.go b/sdk/rotation/schedule_test.go new file mode 100644 index 0000000000..b8e7fc75c8 --- /dev/null +++ b/sdk/rotation/schedule_test.go @@ -0,0 +1,48 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package rotation + +import ( + "testing" + "time" +) + +func TestParseSchedule(t *testing.T) { + // Actual schedule-parsing tests are the responsibility of the library, + // (currently robfig/cron), but here are some cases for our specific functionality + cases := []struct { + name string + in string + shouldErr bool + location *time.Location + }{ + {"force local to utc", "* * * * *", false, time.UTC}, + {"seconds are invalid", "* * * * * *", true, nil}, + + // Specifically override this usage + {"custom timezone", "CRON_TZ=Asia/Tokyo * * * * *", false, time.UTC}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + sched, err := DefaultScheduler.Parse(c.in) + if c.shouldErr { // should-err tests end here no matter what + if err == nil { + t.Error("should have errored, but didn't") + } else { + return + } + } + + if err != nil { + t.Errorf("got unexpected error: %v", err) + } + + // check the tz + if sched.Location.String() != c.location.String() { + t.Errorf("wrong tz, expected %s, got %s", c.location.String(), sched.Location.String()) + } + }) + } +}