[Alerting v2] [Rule authoring] Enforce max values and validation to rule form duration fields#258526
Conversation
jasonrhodes
left a comment
There was a problem hiding this comment.
A few testing questions, non-blocking, max value handling LGTM in general.
| function parseDurationToMs(value: string): number { | ||
| const match = DURATION_RE.exec(value); | ||
| if (!match) return NaN; | ||
| return parseInt(match[1], 10) * DURATION_UNIT_TO_MS[match[2]]; | ||
| } |
There was a problem hiding this comment.
Do we want a few unit tests for this function or only test it via the others?
There was a problem hiding this comment.
+1 for unit tests for all validation functions.
| expect(result.success).toBe(true); | ||
| }); | ||
|
|
||
| it('rejects schedule.every exceeding 365d', () => { |
There was a problem hiding this comment.
Since these are unit tests and relatively cheap, could we make sure we also test something like "55w" fails, "500m" succeeds ... to make sure the date logic is being fully parsed and not just comparing 366 > 365 etc?
jasonrhodes
left a comment
There was a problem hiding this comment.
Had a question about the parseDuration methods
| let showIntervalWarning = false; | ||
| if (field.value && scheduleEvery) { | ||
| try { | ||
| showIntervalWarning = parseDuration(field.value) < parseDuration(scheduleEvery); |
There was a problem hiding this comment.
This parseDuration isn't the one that's created in this PR and used in the validation, right? Looks like the new one allows ms and w units but the existing one doesn't. Is this going to cause sneaky bugs?
ApprovabilityVerdict: Needs human review All changed files are owned by @elastic/rna-project-team but the author is not a member. Additionally, an open review comment raises a substantive concern about potential inconsistency between two different parseDuration implementations that could cause bugs. You can customize Macroscope's approvability policy. Learn more. |
💔 Build Failed
Failed CI Steps
Test Failures
Metrics [docs]Public APIs missing comments
Async chunks
History
|
7c92fc4
into
elastic:alerting_v2
elastic#258526 introduced a 1m minimum for schedule.every which broke the Scout episode_lifecycle tests that use a 5s interval. Lower the floor to 5s so existing tests (and short-interval rules) remain valid. Removes one redundant "cross-unit" test case that no longer applies at the 5s boundary. Made-with: Cursor
## Summary Fixes a regression introduced by #258526, which added a `MIN_SCHEDULE_INTERVAL = '1m'` server-side validation on `schedule.every`. This broke the Scout `episode_lifecycle` tests that create rules with a `5s` schedule interval — the API now rejects those requests, causing the "should track multiple groups independently" test (and others in the suite) to fail. **Fix:** Lower `MIN_SCHEDULE_INTERVAL` from `'1m'` to `'5s'` in `constants.ts`. Update corresponding unit tests to reflect the new boundary. **Test removal:** Removes one `createRuleDataSchema` test case ("rejects schedule.every below 1m via cross-unit (59s)") that was meant to validate cross-unit comparison but wasn't doing that for 1m so was an unnecessary test before and after these PR changes. (if the min value had been 2m, you could test failures at 1m and at 95s, and that's cross-unit testing ... but when the value is 1m and the lowest unit we allow is seconds, there's no cross-unit test possible). A follow-up issue will be created to discuss whether `5s` is the right long-term minimum or if this should be configurable per environment. ## Test plan - [x] `rule_data_schema.test.ts` — 95 tests pass - [x] `validation.test.ts` — 48 tests pass Made with [Cursor](https://cursor.com)
Summary
Adds maximum duration constraints to all duration fields in the alerting v2 rule form, closing a validation gap where a direct API call could submit arbitrarily large values that would pass server-side validation undetected. Also enforces a minimum schedule interval and warns when the lookback window is shorter than the execution interval.
Problem: Duration fields (
schedule.every,schedule.lookback,state_transition.pending_timeframe,state_transition.recovering_timeframe) were only validated for format correctness (e.g."5m","1h"). There was no upper or lower bound, so a malformed or malicious API payload could submit values like"9999d"or"1ms"and they would be accepted by both the client and server.Solution:
Server-side (
@kbn/alerting-v2-schemas):MAX_DURATION = '365d'andMIN_SCHEDULE_INTERVAL = '1m'constants inconstants.tsvalidateMaxDuration(value, max),validateMinDuration(value, min), andparseDurationToMs(value)tovalidation.ts, converting duration strings to milliseconds for comparisondurationSchemaincommon.tsto enforceMAX_DURATIONon every duration field automaticallyscheduleEverySchemainrule_data_schema.tsto additionally enforceMIN_SCHEDULE_INTERVALonschedule.everyClient-side (
alerting-v2-rule-form):ScheduleFieldvalidates both min (1m) and max (365d) onschedule.everyLookbackWindowFieldvalidates max (365d) onschedule.lookbackand shows a plain-text help warning when the lookback is shorter than the schedule intervalStateTransitionTimeframeFieldvalidates max (365d) onpending_timeframeandrecovering_timeframe@kbn/alerting-v2-schemas, keeping client and server in syncThe value
365dwas chosen to be intentionally generous: no legitimate rule would need a schedule or timeframe exceeding one year. It is easier to relax a constraint later than to introduce one after the fact (which would be a breaking change for rules already storing larger values).The decision for these changes has been captured in this doc.
Test plan
validation.test.tssuite coveringparseDurationToMs,validateMaxDuration, andvalidateMinDurationincluding cross-unit cases (55wexceeds365d,500mis within limit)schedule.everyrejects values below1m(e.g.30s,59s) and above365din bothcreateRuleDataSchemaandupdateRuleDataSchemaschedule.lookback,pending_timeframe, andrecovering_timeframereject values exceeding365d30sin Schedule field and confirm min error appears9999din Schedule / Lookback / Pending timeframe / Recovering timeframe fields and confirm max error appears