Skip to content

Commit 0364541

Browse files
authored
fix(cron): anchor regex and accept full cron syntax (#1577)
The cron validator's regex lacked `^...$` anchors, so any string containing a cron-like substring (e.g. `"random text @daily more text"`, `"prefix @every 1h suffix"`, `"x 1 2 3 4 5 y"`) was accepted as a valid cron expression. Anchoring alone wasn't sufficient — the original field pattern only recognized plain numeric forms and was getting away with it via substring matching. Several existing positive test cases (`?`, `L`, `MON-FRI`, `#`, multi-field expressions with year) only passed because the regex matched a numeric fragment of the input. The field pattern is now expanded to accept the documented cron alphabet (`*`, `?`, digits, letters, `,`, `/`, `-`, `#`, `L`, `W`) while still rejecting bare single letters like "x" that aren't valid in any cron dialect. Negative test cases added to lock in the new behavior, with a note documenting remaining false positives that would require a real cron parser to reject (out-of-range values, nonsense alphabetic tokens, etc). - Fixes #1576 ## Fixes Or Enhances **Make sure that you've checked the boxes below before you submit PR:** - [x] Tests exist or have been written that cover this particular change. @go-playground/validator-maintainers Signed-off-by: Ahmed Kamal <ahmed@ahmedkamal.io>
1 parent 8eb2659 commit 0364541

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

regexes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const (
7777
cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html
7878
mongodbIdRegexString = "^[a-f\\d]{24}$"
7979
mongodbConnStringRegexString = "^mongodb(\\+srv)?:\\/\\/(([a-zA-Z\\d]+):([a-zA-Z\\d$:\\/?#\\[\\]@]+)@)?(([a-z\\d.-]+)(:[\\d]+)?)((,(([a-z\\d.-]+)(:(\\d+))?))*)?(\\/[a-zA-Z-_]{1,64})?(\\?(([a-zA-Z]+)=([a-zA-Z\\d]+))(&(([a-zA-Z\\d]+)=([a-zA-Z\\d]+))?)*)?$"
80-
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|((\*|\d+)(\/|-)\d+)|\d+|\*) ?){5,7})`
80+
cronRegexString = `^((@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|(([A-Za-z0-9*?][A-Za-z0-9*?/,#L-]+|[*?0-9])( +([A-Za-z0-9*?][A-Za-z0-9*?/,#L-]+|[*?0-9])){4,6}))$`
8181
spicedbIDRegexString = `^(([a-zA-Z0-9/_|\-=+]{1,})|\*)$`
8282
spicedbPermissionRegexString = "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$"
8383
spicedbTypeRegexString = "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$"

validator_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15163,6 +15163,24 @@ func TestCronExpressionValidation(t *testing.T) {
1516315163
{"0 15 10 ? * 6#3", "cron", true},
1516415164
{"0 */15 * * *", "cron", true},
1516515165
{"wrong", "cron", false},
15166+
// The regex must match the entire string, not a substring containing
15167+
// something cron-like. Without `^...$` anchors, arbitrary text wrapped
15168+
// around a valid cron expression would falsely validate.
15169+
{"random text @daily more text", "cron", false},
15170+
{"foo @yearly bar", "cron", false},
15171+
{"prefix @every 1h suffix", "cron", false},
15172+
{"x 1 2 3 4 5 y", "cron", false},
15173+
{"hello world this string has 1 2 3 4 5 numbers", "cron", false},
15174+
{"not at all valid; trailing junk: * * * * *", "cron", false},
15175+
// Known limitations: the following inputs still pass because the
15176+
// regex validates cron *syntax*, not semantics. Catching them would
15177+
// require a real cron parser (per-field value ranges, an enumerated
15178+
// list of valid alphabetic tokens like MON/TUE/JAN/FEB, etc.):
15179+
// "60 25 32 13 7" - all numeric fields out of range
15180+
// "foo bar baz qux quux" - nonsense alphabetic tokens, all 2+ chars
15181+
// "5- * * * *" - field with trailing separator
15182+
// "0,,1 * * * *" - field with empty list slot
15183+
// "@every 0s" - zero-duration interval
1516615184
}
1516715185

1516815186
validate := New()

0 commit comments

Comments
 (0)