Skip to content

fix(alert): match the alert-rule search term literally instead of as LIKE wildcards - #4667

Closed
btlqql wants to merge 1 commit into
apache:rocketmq-studiofrom
btlqql:fix/btl-alert-search-like-escape
Closed

btlqql wants to merge 1 commit into
apache:rocketmq-studiofrom
btlqql:fix/btl-alert-search-like-escape

Conversation

@btlqql

@btlqql btlqql commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Which Issue(s) This PR Fixes

Brief Description

MybatisPlusAlertRepository bound the raw search term into .like(...) in both paged rule feeds — ruleQuery (server/src/main/java/org/apache/rocketmq/studio/ops/alert/MybatisPlusAlertRepository.java:84) and findRulesPage (:94 and :96) — so the term was interpreted as a LIKE pattern instead of as literal text: % matched any run of characters, _ matched any single character, and \ escaped whatever followed it. Searching for a rule whose name or metric contains a percent sign or an underscore therefore listed unrelated rules, and a term containing a backslash could match nothing at all.

The pattern is now built from an escaped term (\, % and _ escaped), the same way the existing QueryHistoryService.escapeLike house pattern does it, with the helper kept local to the file that needs it. Both paged searches are covered: findRulePage (name only) and findRulesPage (name OR metric). A term without wildcard characters produces exactly the same pattern as before, so the existing hasBusinessRulePageFilters expectation (%lag%) is unchanged.

How Did You Test This Change?

Test written first and run against the unmodified tree (red):

$ cd server && mvn -B -ntp test -Dtest=MybatisPlusAlertRepositoryTest
[ERROR] Tests run: 18, Failures: 2, Errors: 0, Skipped: 0
[ERROR]   MybatisPlusAlertRepositoryTest.findRulePageShouldEscapeLikeWildcardsInTheSearchTermTest:209
Expecting actual:
  {"MPGENVAL1"="%a%b_c\d%"}
to contain value:
  "%a\%b\_c\\d%"
[ERROR]   MybatisPlusAlertRepositoryTest.findRulesPageShouldEscapeLikeWildcardsInTheSearchTermTest:225
Expecting actual:
  {"MPGENVAL1"=true, "MPGENVAL2"="%50%_off%", "MPGENVAL3"="%50%_off%", "MPGENVAL4"="BUSINESS"}
to contain value:
  "%50\%\_off%"
[ERROR] Tests run: 18, Failures: 2, Errors: 0, Skipped: 0
[INFO] BUILD FAILURE

After the fix (green):

$ cd server && mvn -B -ntp test -Dtest=MybatisPlusAlertRepositoryTest
[INFO] You have 0 Checkstyle violations.
[INFO] Tests run: 18, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

Neighbouring classes, to show the change does not disturb the paged feeds or the controllers:

$ cd server && mvn -B -ntp test -Dtest=AlertServiceTest,AlertRuleControllerTest,SystemAlertControllerTest,ClusterAlertRuleControllerTest,AlertRuleAssetServiceTest
[INFO] Tests run: 133, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

Test coverage:

  • findRulePageShouldEscapeLikeWildcardsInTheSearchTermTest — searches for a%b_c\d and asserts the wrapper binds %a\%b\_c\\d%, i.e. the wildcard characters are escaped and the backslash itself is escaped first.
  • findRulesPageShouldEscapeLikeWildcardsInTheSearchTermTest — the name-or-metric feed: searching " 50%_off " binds the trimmed, escaped %50\%\_off% to both columns.
  • Both tests capture the QueryWrapper with an ArgumentCaptor (calling getSqlSegment() before getParamNameValuePairs()) and assert the bound parameter, so they exercise the SQL that would be sent and need no database.

Checklist

  • One coherent change; unrelated modifications are not bundled in
  • Commit subject follows Conventional Commits (fix:)
  • Tests added or updated for non-trivial changes, test methods named ...Test
  • New UI text has both Chinese and English entries under web/src/i18n/ — not applicable, no UI text added
  • Architecture constraints stay green (mvn test runs the ArchUnit checks)
  • New source files carry the ASF license header — no new source files
  • Documentation touched where behaviour changed — not applicable, the search contract is unchanged for terms without wildcard characters

Overlap with another open pull request

#4458 (escape LIKE wildcards in every search and name the escape character, by 123123213weqw) changes this
same file for the same root cause, as part of one patch that covers every LIKE predicate in the repository.
Measured with git merge-tree --write-tree <this head> <its head>: the two branches conflict in
MybatisPlusAlertRepository.java. Both sides merge into the current trunk individually (merge-tree exits 0 for each against
rocketmq-studio), so this is a genuine collision between two patches to the same lines rather than one of us
being stale. Whichever lands second resolves it mechanically, and if #4458 is merged first this change is
redundant for server/src/main/java/org/apache/rocketmq/studio/ops/alert/MybatisPlusAlertRepository.java and can be closed.

One correction, because an earlier version of this paragraph had it wrong: #4458's base is
rocketmq-studio (the same trunk this change targets), not master. The remaining difference is style - this
patch escapes the term inside the existing query builder, in the style the repository already uses
(QueryHistoryService.escapeLike), instead of introducing a shared utility.

…LIKE wildcards

MybatisPlusAlertRepository bound the raw search term into .like(...) in both
paged rule feeds: ruleQuery (line 84) and findRulesPage (lines 94 and 96). The
term was therefore interpreted as a LIKE pattern rather than as literal text:
'%' matched any run of characters, '_' matched any single character and '\'
escaped the character after it. Searching for a rule whose name or metric
contains a percent sign or an underscore listed unrelated rules, and a term
containing a backslash could match nothing at all.

Escape '\', '%' and '_' before the pattern is built, following the existing
QueryHistoryService.escapeLike house pattern, and keep the helper local to the
file. Both paged searches are covered: findRulePage (name) and findRulesPage
(name OR metric).

Test: MybatisPlusAlertRepositoryTest#findRulePageShouldEscapeLikeWildcardsInTheSearchTermTest
and #findRulesPageShouldEscapeLikeWildcardsInTheSearchTermTest capture the
QueryWrapper and assert the bound parameter value; both fail with the unescaped
pattern before the fix and pass after it.

@RockteMQ-AI RockteMQ-AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Fixes SQL LIKE wildcard injection in alert rule search — %, _ and \ in search terms are now escaped before binding to the LIKE predicate, so users get literal matching instead of pattern matching.

Clean, focused fix with good test coverage (ArgumentCaptor approach verifies the exact bound values). The escape order is correct (backslash first, then wildcards). LGTM.


Automated review by github-manager-bot

@lizhimins lizhimins left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The escaping itself is right, but this PR cannot land as it stands — it collides with #4458 and is a strict subset of it.

Concretely:

  1. Same lines as #4458. Both PRs rewrite MybatisPlusAlertRepository.java:84/94/96 (the .like(...) calls on name / metric / the third search column). git merge-tree between the two branches reports a conflict on exactly those lines, so only one of them can go in unchanged. #4458 is still open and was submitted earlier.
  2. Coverage. #4458 escapes nine LIKE call sites across the search paths; this one covers the three in the alert repository. Everything here is already in there.
  3. Missing ESCAPE clause. The new private escapeLike (line 89) escapes \, % and _ in the bound parameter, but the predicate is still emitted as a plain LIKE ? with no ESCAPE '\' clause. MySQL's default escape character happens to be \, so it works today by accident rather than by contract — and it breaks on any deployment that sets a different sql_mode/NO_BACKSLASH_ESCAPES. #4458 has the same gap, so this is worth fixing once, in one place.

What would make this actionable: rebase on top of #4458 once it lands and re-submit only what it still misses (if anything), with an explicit ESCAPE clause on the predicates. Until then there is nothing to merge that #4458 does not already carry, so I am marking this as requiring changes rather than merging or closing it outright.

@btlqql

btlqql commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed comparison. I confirmed that #4458 is still open and that this branch overlaps its alert-repository hunk, so I will not push another competing implementation onto this PR. I will wait for #4458 to be resolved, then rebase on the resulting rocketmq-studio state and keep only an independently useful remainder, including an explicit ESCAPE clause if that is still missing. I am leaving the PR open rather than claiming the current subset is mergeable.

@btlqql

btlqql commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

Closing this overlapping PR after checking #4458's current head. It covers the same alert-rule LIKE predicates and names the escape character explicitly with ESCAPE CHAR(92); there is no independent change left in this branch. Thanks for the review.

@btlqql btlqql closed this Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants