This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 39d705248 fix(alert): reject overflowing rule durations (#2649)
39d705248 is described below
commit 39d705248babea4c86ef1e365f56d8bd8a482577
Author: btlqql <[email protected]>
AuthorDate: Wed Sep 2 17:06:30 2026 +0800
fix(alert): reject overflowing rule durations (#2649)
---
.../studio/ops/alert/AlertRuleDuration.java | 34 ++++++++++++----------
.../studio/ops/alert/NativeAlertRulePolicy.java | 2 ++
.../studio/ops/alert/AlertRuleDurationTest.java | 12 ++++++++
.../ops/alert/NativeAlertRulePolicyTest.java | 10 +++++++
4 files changed, 43 insertions(+), 15 deletions(-)
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDuration.java
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDuration.java
index fa67e1b43..dbacfbb90 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDuration.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDuration.java
@@ -24,26 +24,30 @@ final class AlertRuleDuration {
if (!StringUtils.hasText(value)) {
return Duration.ZERO;
}
- Matcher matcher = PART.matcher(value.trim());
- Duration result = Duration.ZERO;
- int end = 0;
- while (matcher.find()) {
- if (matcher.start() != end) {
- throw invalid(value);
+ try {
+ Matcher matcher = PART.matcher(value.trim());
+ Duration result = Duration.ZERO;
+ int end = 0;
+ while (matcher.find()) {
+ if (matcher.start() != end) {
+ throw invalid(value);
+ }
+ long amount;
+ try {
+ amount = Long.parseLong(matcher.group(1));
+ } catch (NumberFormatException error) {
+ throw invalid(value);
+ }
+ result = result.plus(toDuration(amount, matcher.group(2),
value));
+ end = matcher.end();
}
- long amount;
- try {
- amount = Long.parseLong(matcher.group(1));
- } catch (NumberFormatException error) {
+ if (end != value.trim().length()) {
throw invalid(value);
}
- result = result.plus(toDuration(amount, matcher.group(2), value));
- end = matcher.end();
- }
- if (end != value.trim().length()) {
+ return result;
+ } catch (ArithmeticException error) {
throw invalid(value);
}
- return result;
}
private static BusinessException invalid(String value) {
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicy.java
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicy.java
index 18d75d261..84aee5fe0 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicy.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicy.java
@@ -74,6 +74,8 @@ final class NativeAlertRulePolicy {
if (StringUtils.hasText(rule.getTopic()) &&
!TOPIC_SCOPED_METRICS.contains(rule.getMetric())) {
throw new BusinessException(400, "topic is not supported for
metric " + rule.getMetric());
}
+ AlertRuleDuration.parse(rule.getDuration());
+ AlertRuleDuration.parse(rule.getReminderInterval());
if (rule.getConsecutiveSamples() < 1) {
throw new BusinessException(400, "consecutiveSamples must be at
least 1");
}
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDurationTest.java
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDurationTest.java
index a22233149..463a93729 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDurationTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleDurationTest.java
@@ -6,11 +6,13 @@
*/
package org.apache.rocketmq.studio.ops.alert;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
class AlertRuleDurationTest {
@Test
@@ -18,4 +20,14 @@ class AlertRuleDurationTest {
assertThat(AlertRuleDuration.parse("1h30m")).isEqualTo(Duration.ofMinutes(90));
assertThat(AlertRuleDuration.parse(null)).isEqualTo(Duration.ZERO);
}
+
+ @Test
+ void rejectsDurationsThatOverflowTest() {
+ assertThatThrownBy(() ->
AlertRuleDuration.parse("9223372036854775807y"))
+ .isInstanceOf(BusinessException.class)
+ .hasMessageContaining("Invalid alert duration");
+ assertThatThrownBy(() ->
AlertRuleDuration.parse("9223372036854775807s9223372036854775807s"))
+ .isInstanceOf(BusinessException.class)
+ .hasMessageContaining("Invalid alert duration");
+ }
}
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicyTest.java
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicyTest.java
index 88e0c3c79..a2de0f1f2 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicyTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertRulePolicyTest.java
@@ -107,6 +107,16 @@ class NativeAlertRulePolicyTest {
}
}
+ @Test
+ void rejectsOverflowingNativeRuleDurationsBeforePersistenceTest() {
+ assertThatThrownBy(() ->
NativeAlertRulePolicy.validate(rule(AlertDomain.CLUSTER, "broker.availability")
+ .instanceId("local").duration("9223372036854775807y").build()))
+
.isInstanceOf(BusinessException.class).hasMessageContaining("Invalid alert
duration");
+ assertThatThrownBy(() ->
NativeAlertRulePolicy.validate(rule(AlertDomain.CLUSTER, "broker.availability")
+
.instanceId("local").reminderInterval("9223372036854775807y").build()))
+
.isInstanceOf(BusinessException.class).hasMessageContaining("Invalid alert
duration");
+ }
+
private static AlertRuleVO.AlertRuleVOBuilder rule(AlertDomain domain,
String metric) {
return AlertRuleVO.builder().domain(domain).name("Test
rule").metric(metric).consecutiveSamples(1);
}