Skip to content

[ResponseOps] ES|QL query rule executor silently rewrites the saved query via parse+pretty-print#275231

Merged
doakalexi merged 12 commits into
elastic:mainfrom
doakalexi:bug/appendLimitToQuery-rewrites-query
Jul 2, 2026
Merged

[ResponseOps] ES|QL query rule executor silently rewrites the saved query via parse+pretty-print#275231
doakalexi merged 12 commits into
elastic:mainfrom
doakalexi:bug/appendLimitToQuery-rewrites-query

Conversation

@doakalexi

@doakalexi doakalexi commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Resolves #273173

Summary

When we execute an ES|QL rule we call, appendLimitToQuery, which parses the query, and re-emits it with the limit via BasicPrettyPrinter from @elastic/esql. Using the pretty printer drops parentheses that change the AST shape, so calculations that depend on grouping with same-precedence binary operators (*// or +/-) are rewritten and evaluate to a different value than what the user authored.

This PR updates appendLimitToQuery to find the end of the actual query and strip off any comments that would interfere with appending the limit and returns the rest of the query as written with the new limit.

Checklist

To verify

  1. Create a few different ES|QL rules. Use queries that include parentheses and order of operations calculations.
  2. Let the rules run
  3. Verify that that results of the rule queries match what is expected.

@doakalexi doakalexi changed the title Update appendLimitToQuery to just remove the trailing comments [ResponseOps] ES|QL query rule executor silently rewrites the saved query via parse+pretty-print Jun 29, 2026
@doakalexi doakalexi added release_note:fix Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t// backport:version Backport to applied version labels v9.5.0 v9.4.4 labels Jun 29, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The new token-based appendLimitToQuery approach is sound and matches the existing antlr4 token-channel pattern used in kbn-esql-language/.../lexer_scope.ts, and antlr4 is a runtime dependency so the import is safe. One inline finding: a leftover casing mismatch in a CSV generator test assertion that lines up with the still-failing CI Jest test.

Generated by Claude Reviewer for issue #275231 · 182.3 AIC · ⌖ 10.3 AIC · ⊞ 3.9K

Comment thread src/platform/packages/private/kbn-generate-csv/src/generate_csv_esql.test.ts Outdated
doakalexi and others added 4 commits June 29, 2026 10:08
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…akalexi/kibana into bug/appendLimitToQuery-rewrites-query
@doakalexi
doakalexi marked this pull request as ready for review June 29, 2026 19:50
@doakalexi
doakalexi requested review from a team as code owners June 29, 2026 19:50
@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

Pinging @elastic/response-ops (Team:ResponseOps)

@stratoula

Copy link
Copy Markdown
Contributor

We recently did some changes and we include parenthesis at the AST so @bartoval will help here

@bartoval

Copy link
Copy Markdown
Contributor

We recently did some changes and we include parenthesis at the AST so @bartoval will help here

This Pr should solve the parens problems elastic/esql-js#130. This fix should be active on Kibana soon. https://github.com/elastic/kibana/pull/275286/changes#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519R143

@doakalexi

Copy link
Copy Markdown
Contributor Author

Thanks @stratoula and @bartoval! I am wondering what you think about using BasicPrettyPrinter to remove comments from the query like we were doing before? Maybe it's not worth the risk of accidentally alerting the query? and this approach I have in the PR of just stripping off any comments at the end is maybe safer?

@adcoelho adcoelho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

response-ops changes OK, just some tests

@stratoula

Copy link
Copy Markdown
Contributor

Thanks @stratoula and @bartoval! I am wondering what you think about using BasicPrettyPrinter to remove comments from the query like we were doing before? Maybe it's not worth the risk of accidentally alerting the query? and this approach I have in the PR of just stripping off any comments at the end is maybe safer?

Sorry Alexi, I am not sure I follow 😅 (maybe because it is late). Can you elaborate?

@doakalexi

Copy link
Copy Markdown
Contributor Author

Thanks @stratoula and @bartoval! I am wondering what you think about using BasicPrettyPrinter to remove comments from the query like we were doing before? Maybe it's not worth the risk of accidentally alerting the query? and this approach I have in the PR of just stripping off any comments at the end is maybe safer?

Sorry Alexi, I am not sure I follow 😅 (maybe because it is late). Can you elaborate?

That's my bad, sorry! I wanted to get your thoughts about keeping this PR open with this change to appendLimitToQuery. Even though @bartoval's change will fix the issue in BasicPrettyPrinter, I am wondering if you think the approach in this PR to move away from BasicPrettyPrinter in appendLimitToQuery is worth keeping to prevent other bugs like this from happening? I don't think it's super necessary to use the pretty printer if we can just find the end of the query and remove any trailing comments and append the limit?

I'm also wondering if change in @bartoval's PR would be able to backported? bc I think we will want to backport a fix for this as well

@bartoval

bartoval commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Thanks @stratoula and @bartoval! I am wondering what you think about using BasicPrettyPrinter to remove comments from the query like we were doing before? Maybe it's not worth the risk of accidentally alerting the query? and this approach I have in the PR of just stripping off any comments at the end is maybe safer?

Sorry Alexi, I am not sure I follow 😅 (maybe because it is late). Can you elaborate?

That's my bad, sorry! I wanted to get your thoughts about keeping this PR open with this change to appendLimitToQuery. Even though @bartoval's change will fix the issue in BasicPrettyPrinter, I am wondering if you think the approach in this PR to move away from BasicPrettyPrinter in appendLimitToQuery is worth keeping to prevent other bugs like this from happening? I don't think it's super necessary to use the pretty printer if we can just find the end of the query and remove any trailing comments and append the limit?

I'm also wondering if change in @bartoval's PR would be able to backported? bc I think we will want to backport a fix for this as well

Hello @doakalexi .
If you want a raw query, Does just doing someting like

const trimmedQuery = queryString.trimEnd();
return `${trimmedQuery}\n| LIMIT ${limit}`;

cause you problems?

@doakalexi

Copy link
Copy Markdown
Contributor Author

If you want a raw query, Does just doing someting like

const trimmedQuery = queryString.trimEnd();
return `${trimmedQuery}\n| LIMIT ${limit}`;

cause you problems?

Thanks @bartoval! It looks like ${trimmedQuery}\n| LIMIT ${limit} would work too. Do you think I should go ahead update to appendLimitToQuery with that suggestion?

@bartoval

bartoval commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

If you want a raw query, Does just doing someting like

const trimmedQuery = queryString.trimEnd();
return `${trimmedQuery}\n| LIMIT ${limit}`;

cause you problems?

Thanks @bartoval! It looks like ${trimmedQuery}\n| LIMIT ${limit} would work too. Do you think I should go ahead update to appendLimitToQuery with that suggestion?

If you want a raw query, Does just doing someting like

const trimmedQuery = queryString.trimEnd();
return `${trimmedQuery}\n| LIMIT ${limit}`;

cause you problems?

Thanks @bartoval! It looks like ${trimmedQuery}\n| LIMIT ${limit} would work too. Do you think I should go ahead update to appendLimitToQuery with that suggestion?

Does it make sense to have this utils in this package? it seems we already have appendToESQLQuery in utils.ts
..or you can just do `${queryString.trimEnd()}\n| LIMIT ${limit}`; directly

I see from past commits that you implemented this function and all the consumers (or part of it) to use it.

@doakalexi

doakalexi commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Does it make sense to have this utils in this package? it seems we already have appendToESQLQuery in utils.ts
..or you can just do ${queryString.trimEnd()}\n| LIMIT ${limit}; directly

I think it makes sense to keep appendLimitToQuery, I think there a couple places that use the function already and it's nice to have a consistent way to append a limit. but I can remove it if you think it's not useful too

Thanks for the suggestion, I updated to use \n in this commit, 211df81

@bartoval

bartoval commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Does it make sense to have this utils in this package? it seems we already have appendToESQLQuery in utils.ts
..or you can just do ${queryString.trimEnd()}\n| LIMIT ${limit}; directly

I think it makes sense to keep appendLimitToQuery, I think there a couple places that use the function already and it's nice to have a consistent way to append a limit. but I can remove it if you think it's not useful too

Thanks for the suggestion, I updated to use \n in this commit, 211df81

That works for me; I'll leave the approval to @stratoula .

In any case, I am restating my thoughts above-> This existing function https://github.com/bartoval/kibana/blob/main/src/platform/packages/shared/kbn-esql-utils/src/utils/append_to_query/utils.ts#L90 It works in a similar way.

Just change your 2 consumers to

query = appendToESQLQuery(this.job.query.esql, `| LIMIT ${maxRows}`);
query = appendToESQLQuery(this.job.query.esql, `| LIMIT ${alertLimit}`);

Then we can delete this file and the test

@stratoula stratoula left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The appendLimitToQuery is only used in 2 consumers. I will keep it thought to esql-utils:

  • it is a common thing to do and I want to change it with the composer api
  • I prefer to have one place to add the utils and not have multiple solutions across consumers

Alexi the solution is ok for now. Can you just remove the wrong test I point out?

);
});

it('removes trailing block comments before appending the limit', () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is wrong, it doesnt remove them. I dont think we need this test, can we remove this please?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks @stratoula and @bartoval for your help on this! Test removed in this commit, 87df6b0

@doakalexi
doakalexi enabled auto-merge (squash) July 2, 2026 16:03
@kibanamachine

Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Jest Tests #12 / AlertFlyoutOverviewTab wraps the overview tab in KibanaContextProvider and ReactQueryClientProvider
  • [job] [logs] Jest Tests #8 / EntryItem displays DOES NOT MATCH select option as disabled if doesNotMatchDisabled=true
  • [job] [logs] Scout Lane #59 - serverless-observability_logs_essentials / uiam_local / local-serverless-observability_logs_essentials - [NON-MKI] UIAM API Keys grant and invalidate functions - should be able to grant a UIAM API key with valid UIAM credentials
  • [job] [logs] Scout Lane #64 - serverless-security_complete / default / local-serverless-security_complete - Saved Objects Tagging - usage collector - reports correct tag usage counts via the telemetry endpoint
  • [job] [logs] Scout Lane #4 - stateful-classic / default / local-stateful-classic - Discover tabs - opening a new tab - should create a new tab in classic mode
  • [job] [logs] Scout Lane #4 - stateful-classic / default / local-stateful-classic - Metrics in Discover - Inspect - should open inspector and navigate through views and tabs
  • [job] [logs] Scout Lane #15 - stateful-classic / default / local-stateful-classic - Saved query menu — CRUD (Discover) - save, load, update, save-as-new, delete via the popover
  • [job] [logs] Scout Lane #13 - stateful-classic / default / local-stateful-classic - UptimeIntegrationDeprecation - returns true when non-managed synthetics policies exist

Metrics [docs]

✅ unchanged

History

@doakalexi
doakalexi merged commit 89d065f into elastic:main Jul 2, 2026
39 checks passed
@kibanamachine

Copy link
Copy Markdown
Contributor

Starting backport for target branches: 9.4

https://github.com/elastic/kibana/actions/runs/28604635640

@kibanamachine

Copy link
Copy Markdown
Contributor

💚 All backports created successfully

Status Branch Result
9.4

Note: Successful backport PRs will be merged automatically after passing CI.

Questions ?

Please refer to the Backport tool documentation

kibanamachine added a commit that referenced this pull request Jul 2, 2026
…aved query via parse+pretty-print (#275231) (#276032)

# Backport

This will backport the following commits from `main` to `9.4`:
- [[ResponseOps] ES|QL query rule executor silently rewrites the saved
query via parse+pretty-print
(#275231)](#275231)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Alexi
Doak","email":"109488926+doakalexi@users.noreply.github.com"},"sourceCommit":{"committedDate":"2026-07-02T16:11:59Z","message":"[ResponseOps]
ES|QL query rule executor silently rewrites the saved query via
parse+pretty-print (#275231)\n\nResolves
https://github.com/elastic/kibana/issues/273173\n\n## Summary\n\nWhen we
execute an ES|QL rule we call, `appendLimitToQuery`, which\nparses the
query, and re-emits it with the limit via BasicPrettyPrinter\nfrom
@elastic/esql. Using the pretty printer drops parentheses that\nchange
the AST shape, so calculations that depend on grouping
with\nsame-precedence binary operators (*// or +/-) are rewritten and
evaluate\nto a different value than what the user authored.\n\nThis PR
updates `appendLimitToQuery` to find the end of the actual query\nand
strip off any comments that would interfere with appending the
limit\nand returns the rest of the query as written with the new
limit.\n\n\n### Checklist\n\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n\n\n### To
verify\n\n1. Create a few different ES|QL rules. Use queries that
include\nparentheses and order of operations calculations.\n2. Let the
rules run\n3. Verify that that results of the rule queries match what is
expected.\n\n---------\n\nCo-authored-by: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>","sha":"89d065fa2b2977d852775627599ae73506d611ad","branchLabelMapping":{"^v9.5.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:ResponseOps","backport:version","v9.5.0","v9.4.4"],"title":"[ResponseOps]
ES|QL query rule executor silently rewrites the saved query via
parse+pretty-print","number":275231,"url":"https://github.com/elastic/kibana/pull/275231","mergeCommit":{"message":"[ResponseOps]
ES|QL query rule executor silently rewrites the saved query via
parse+pretty-print (#275231)\n\nResolves
https://github.com/elastic/kibana/issues/273173\n\n## Summary\n\nWhen we
execute an ES|QL rule we call, `appendLimitToQuery`, which\nparses the
query, and re-emits it with the limit via BasicPrettyPrinter\nfrom
@elastic/esql. Using the pretty printer drops parentheses that\nchange
the AST shape, so calculations that depend on grouping
with\nsame-precedence binary operators (*// or +/-) are rewritten and
evaluate\nto a different value than what the user authored.\n\nThis PR
updates `appendLimitToQuery` to find the end of the actual query\nand
strip off any comments that would interfere with appending the
limit\nand returns the rest of the query as written with the new
limit.\n\n\n### Checklist\n\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n\n\n### To
verify\n\n1. Create a few different ES|QL rules. Use queries that
include\nparentheses and order of operations calculations.\n2. Let the
rules run\n3. Verify that that results of the rule queries match what is
expected.\n\n---------\n\nCo-authored-by: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>","sha":"89d065fa2b2977d852775627599ae73506d611ad"}},"sourceBranch":"main","suggestedTargetBranches":["9.4"],"targetPullRequestStates":[{"branch":"main","label":"v9.5.0","branchLabelMappingKey":"^v9.5.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/275231","number":275231,"mergeCommit":{"message":"[ResponseOps]
ES|QL query rule executor silently rewrites the saved query via
parse+pretty-print (#275231)\n\nResolves
https://github.com/elastic/kibana/issues/273173\n\n## Summary\n\nWhen we
execute an ES|QL rule we call, `appendLimitToQuery`, which\nparses the
query, and re-emits it with the limit via BasicPrettyPrinter\nfrom
@elastic/esql. Using the pretty printer drops parentheses that\nchange
the AST shape, so calculations that depend on grouping
with\nsame-precedence binary operators (*// or +/-) are rewritten and
evaluate\nto a different value than what the user authored.\n\nThis PR
updates `appendLimitToQuery` to find the end of the actual query\nand
strip off any comments that would interfere with appending the
limit\nand returns the rest of the query as written with the new
limit.\n\n\n### Checklist\n\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n\n\n### To
verify\n\n1. Create a few different ES|QL rules. Use queries that
include\nparentheses and order of operations calculations.\n2. Let the
rules run\n3. Verify that that results of the rule queries match what is
expected.\n\n---------\n\nCo-authored-by: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>","sha":"89d065fa2b2977d852775627599ae73506d611ad"}},{"branch":"9.4","label":"v9.4.4","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Alexi Doak <109488926+doakalexi@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
MykhailoKondrat pushed a commit to MykhailoKondrat/kibana that referenced this pull request Jul 2, 2026
…uery via parse+pretty-print (elastic#275231)

Resolves elastic#273173

## Summary

When we execute an ES|QL rule we call, `appendLimitToQuery`, which
parses the query, and re-emits it with the limit via BasicPrettyPrinter
from @elastic/esql. Using the pretty printer drops parentheses that
change the AST shape, so calculations that depend on grouping with
same-precedence binary operators (*// or +/-) are rewritten and evaluate
to a different value than what the user authored.

This PR updates `appendLimitToQuery` to find the end of the actual query
and strip off any comments that would interfere with appending the limit
and returns the rest of the query as written with the new limit.


### Checklist

- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios


### To verify

1. Create a few different ES|QL rules. Use queries that include
parentheses and order of operations calculations.
2. Let the rules run
3. Verify that that results of the rule queries match what is expected.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:version Backport to applied version labels release_note:fix Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t// v9.4.4 v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ResponseOps] ES|QL query rule executor silently rewrites the saved query via parse+pretty-print

5 participants