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 51a3424a fix: validate audit log date filters (#567)
51a3424a is described below

commit 51a3424aefab961488199b4eff6942a875c2b080
Author: yx9o <[email protected]>
AuthorDate: Tue Jul 28 20:27:28 2026 +0800

    fix: validate audit log date filters (#567)
    
    * fix: align frontend API success response handling (#429)
    
    * ci: add build workflow and PR review skill (#430)
    
    * fix: connect K8s certificate page to APIs (#440)
    
    * feat: extend translation keys & add useLanguage compatible alias in 
LangContext (#433)
    
    * fix: validate audit query and cleanup parameters (#442)
    
    * chore: fix Dockerfile missing style/ copy and standardize pr-review skill 
(#444)
    
    - Add COPY style ./style to server/Dockerfile so Maven checkstyle can
      find style/rmq_checkstyle.xml during docker compose build
    - Rewrite pr-review SKILL.md with an 8-stage pipeline checklist,
      Dockerfile pre-flight fix step, and [Studio] title format spec
    
    * feat: add centralized ThemeContext and useTheme hook for dark mode 
management (#435)
    
    * fix: preserve SSE framing for AI chat (#438)
    
    * feat: add Prometheus range query adapter (#432)
    
    Add a real Prometheus /api/v1/query_range adapter as the foundation for 
observability (#431): configurable base URL, timeouts, Basic/Bearer auth, error 
mapping, and tests.
    
    * feat: implement login page, auth & AI modules, simplify theme management 
(#473)
    
    Add login page with full auth workflow, Auth/AI API modules, Zustand state, 
and simplified theme management.
    
    * feat: add Ops page (NameServer management, VIPChannel, TLS) (#474)
    
    Add Ops management page for NameServer address management, VIP channel 
toggle, and TLS switch.
    
    * feat: add Producer page (#475)
    
    Add a page to query producer client connections by Topic and Producer Group.
    
    * feat: add AlertManagement page for alert rule operations (#476)
    
    Add alert rule management page: parse/render Prometheus AlertManager YAML 
rules with search, toggle, and CRUD.
    
    * feat: add SslSettings page for SSL/TLS configuration management (#477)
    
    Add SSL/TLS configuration page: SSL toggle, TLS version, 
KeyStore/TrustStore, client auth mode.
    
    * feat: add broker cluster overview page (#479)
    
    Add Broker Cluster overview page with tab-based NameServer/Broker/Proxy 
management and cluster stats.
    
    * feat: add consumer group management page (#480)
    
    Add consumer group management page.
    
    * feat: add lite topic management page (#481)
    
    Add lite topic management page.
    
    * feat: add Proxy management page (#482)
    
    Add Proxy management page (address list, status, TPS, memory, CPU, uptime).
    
    * feat: add LLM Settings configuration page (#483)
    
    Add LLM settings configuration page (provider, apiKey, model, temperature, 
etc.).
    
    * feat: connect frontend pages to backend APIs and align contracts (#445)
    
    Consolidated API-integration work 
(#445,#446,#447,#448,#449,#450,#451,#452,#453,#454,#458,#459,#460,#461,#463).
    
    * feat: add service capabilities and interaction enhancements (#462)
    
    Consolidated service/interaction work 
(#462,#468,#469,#464,#470,#471,#472,#488).
    
    * feat: add preferences persistence, accessibility and env config (#465)
    
    Consolidated preferences/a11y/config work (#465,#466,#485,#486,#487,#484).
    
    * fix: include remaining consolidated frontend changes (#490)
    
    topicService topic API contract, authStore persisted session, vite env 
config.
    
    * fix: align login response contract (#492)
    
    Align frontend LoginResponse type with backend LoginVO contract: change 
flat username/role to nested user.username/admin structure.
    
    * fix: use runtime DNS resolver for Nginx API proxy (#494)
    
    Fix Nginx API proxy failure caused by hardcoded DNS resolver by switching 
to container runtime dynamic resolution.
    
    * feat: enhance i18n support with labelKey-based translations (#495)
    
    Migrate hardcoded Chinese UI text to i18n labelKey pattern, add ~280 
translation entries (zh+en), fix duplicate key compilation errors.
    
    * test: fix frontend baseline assertions (#498)
    
    Fix test assertions to align with backend PageResult contract and current 
i18n labels.
    
    * fix: initialize deploy helpers before validation (#499)
    
    Move logging/error helper initialization before config validation in 
deploy.sh to fix err() undefined when REMOTE_HOST is missing.
    
    * ci: build frontend Docker image (#500)
    
    Add frontend Docker image build to CI workflow to validate Dockerfile/nginx 
deployment path.
    
    * fix: load producer topics from Studio API response (#501)
    
    Fix Producer page topic list to read from Studio API new format 
(data[].name) with backward compatibility for legacy topicList format.
    
    * fix: generate data source keys on creation (#509)
    
    Fix ConcurrentHashMap NPE when creating data sources with null key by 
auto-generating UUID in service layer.
    
    * feat: add producer connection endpoint (#510)
    
    Add producer connection query endpoint with topic/producerGroup filtering, 
returning backward-compatible connectionSet format.
    
    * fix: avoid returning General Settings API key (#512)
    
    Fix security issue where General Settings endpoint returned API key in 
plaintext. Replace with apiKeyConfigured boolean flag and support explicit key 
clearing.
    
    * feat: add catalog-driven read-only tools (#514)
    
    Introduce versioned YAML tool catalog with JSON Schema validation, SHA-256 
digest, deep immutability, and two read-only L1 tool handlers (rmq.cluster.list 
/ rmq.capabilities).
    
    * feat: add LiteTopic backend endpoints (#502)
    
    Add backend stub endpoints for LiteTopic page: list, session details, TTL 
extension, quota, and capability check.
    
    * feat: add ops backend endpoints (#504)
    
    Add ops page backend endpoints: NameServer address management, VIP Channel, 
and TLS switches.
    
    * feat: add proxy address endpoints (#505)
    
    Add proxy address list and add-address endpoints supporting Studio frontend 
form submission.
    
    * feat: add LLM settings endpoints (#506)
    
    Add LLM settings backend endpoints: config read/write, connectivity test, 
and model listing.
    
    * feat: add alert rules YAML endpoint (#507)
    
    Add alert rules Prometheus YAML export endpoint with default RocketMQ alert 
template fallback.
    
    * fix: ACL page API integration (#516)
    
    Wire ACL management page to backend API, add update endpoints for ACL rules 
and users with proper validation.
    
    * fix: sort queried messages by store time (#519)
    
    Sort message query results by storeTime in descending order so latest 
messages appear first.
    
    * feat: add consumer stack diagnostics API (#521)
    
    Add consumer thread stack diagnostics endpoint (GET 
/api/groups/{name}/instances/{clientId}/stack) with Provider/Stub/Service 
layering.
    
    * fix: validate audit log date filters
    
    ---------
    
    Co-authored-by: btlqql <[email protected]>
    Co-authored-by: lizhimins <[email protected]>
    Co-authored-by: zhaohai <[email protected]>
    Co-authored-by: terrancesli <[email protected]>
    Co-authored-by: wizcraft_kris 
<[email protected]>
    Co-authored-by: Loyal-Young <[email protected]>
    Co-authored-by: majialong <[email protected]>
    Co-authored-by: aias00 <[email protected]>
    Co-authored-by: PiliLily <[email protected]>
---
 docs/api-spec.md                                   |  2 ++
 .../rocketmq/studio/ops/audit/AuditService.java    | 15 +++++++-----
 .../studio/ops/audit/AuditServiceTest.java         | 28 +++++++++++++++++-----
 3 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/docs/api-spec.md b/docs/api-spec.md
index e75158f9..2fa9602f 100644
--- a/docs/api-spec.md
+++ b/docs/api-spec.md
@@ -1424,6 +1424,8 @@ GET 
/api/audit-logs?page={page}&pageSize={pageSize}&search={search}&operationTyp
 | `endDate` | `string` | 否 | 结束日期 (YYYY-MM-DD) |
 | `result` | `string` | 否 | 结果过滤: `success` / `failure` |
 
+`startDate` 或 `endDate` 格式错误,以及 `startDate` 晚于 `endDate` 时,接口返回 HTTP 400。
+
 **Response `data`:**
 
 | 字段 | 类型 | 说明 |
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/audit/AuditService.java 
b/server/src/main/java/org/apache/rocketmq/studio/ops/audit/AuditService.java
index 8972bbe7..27588437 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/audit/AuditService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/audit/AuditService.java
@@ -26,6 +26,7 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
 import java.util.List;
 
 @Slf4j
@@ -43,8 +44,11 @@ public class AuditService {
         log.info("Querying audit logs, page={}, pageSize={}, search={}, 
operationType={}, result={}",
                 page, pageSize, search, operationType, result);
 
-        LocalDateTime start = parseDate(startDate, true);
-        LocalDateTime end = parseDate(endDate, false);
+        LocalDateTime start = parseDate(startDate, true, "startDate");
+        LocalDateTime end = parseDate(endDate, false, "endDate");
+        if (start != null && end != null && start.isAfter(end)) {
+            throw new BusinessException(400, "startDate must not be after 
endDate");
+        }
 
         List<AuditRecordVO> allRecords = auditRepository.findAll(search, 
operationType, start, end, result);
         long total = allRecords.size();
@@ -76,16 +80,15 @@ public class AuditService {
         }
     }
 
-    private LocalDateTime parseDate(String dateStr, boolean startOfDay) {
+    private LocalDateTime parseDate(String dateStr, boolean startOfDay, String 
parameterName) {
         if (dateStr == null || dateStr.isEmpty()) {
             return null;
         }
         try {
             LocalDate date = LocalDate.parse(dateStr, 
DateTimeFormatter.ISO_LOCAL_DATE);
             return startOfDay ? date.atStartOfDay() : 
date.atTime(LocalTime.MAX);
-        } catch (Exception e) {
-            log.warn("Failed to parse date: {}", dateStr, e);
-            return null;
+        } catch (DateTimeParseException e) {
+            throw new BusinessException(400, parameterName + " must use 
YYYY-MM-DD");
         }
     }
 }
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/audit/AuditServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/audit/AuditServiceTest.java
index e50eca77..fefb3651 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/audit/AuditServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/audit/AuditServiceTest.java
@@ -188,14 +188,30 @@ class AuditServiceTest {
     }
 
     @Test
-    void queryLogsShouldHandleInvalidDateFormat() {
-        when(auditRepository.findAll(isNull(), isNull(), isNull(), isNull(), 
isNull()))
-                .thenReturn(Collections.emptyList());
+    void queryLogsShouldRejectInvalidStartDate() {
+        assertThatThrownBy(() -> auditService.queryLogs(
+                1, 10, null, null, "invalid-date", null, null))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("startDate must use YYYY-MM-DD")
+                .satisfies(ex -> assertThat(((BusinessException) 
ex).getCode()).isEqualTo(400));
+    }
 
-        PageResult<AuditRecordVO> result = auditService.queryLogs(1, 10, null, 
null, "invalid-date", null, null);
+    @Test
+    void queryLogsShouldRejectInvalidEndDate() {
+        assertThatThrownBy(() -> auditService.queryLogs(
+                1, 10, null, null, null, "2025-02-30", null))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("endDate must use YYYY-MM-DD")
+                .satisfies(ex -> assertThat(((BusinessException) 
ex).getCode()).isEqualTo(400));
+    }
 
-        assertThat(result).isNotNull();
-        assertThat(result.getItems()).isEmpty();
+    @Test
+    void queryLogsShouldRejectReversedDateRange() {
+        assertThatThrownBy(() -> auditService.queryLogs(
+                1, 10, null, null, "2025-02-01", "2025-01-31", null))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("startDate must not be after endDate")
+                .satisfies(ex -> assertThat(((BusinessException) 
ex).getCode()).isEqualTo(400));
     }
 
     @Test

Reply via email to