shashank created CAMEL-26307:
--------------------------------
Summary: camel-jsonpath - an easy predicate with <= or >= is
evaluated as < or >, and one whose quoted value contains an operator word (such
as 'Java in Action') fails
Key: CAMEL-26307
URL: https://issues.apache.org/jira/browse/CAMEL-26307
Project: Camel
Issue Type: Bug
Components: camel-jsonpath
Reporter: shashank
Assignee: shashank
The easy JSONPath syntax ({{store.book.price < 20}}, rewritten by
{{EasyPredicateParser}} into {{$.store.book[?(@.price < 20)]}}) finds the
operator with {{EasyPredicateOperators.getOperatorAtStart}}, which returns the
first operator of its list ({{==, !=, <, <=, >, >=, =~, in, nin, size, empty}})
that the text starts with, after a space. For {{ <= 10}} that is {{<}}: the
parser then skips the operator and the space it expects after it, so the {{=}}
is dropped silently:
{noformat}
price <= 10 -> $..*[?(@.price < 10)] expected
$..*[?(@.price <= 10)]
store.book.price >= 8.95 -> $.store.book[?(@.price > 8.95)]
price <20 -> $..*[?(@.price < 0)] (the first digit
is skipped as if it were the space)
{noformat}
So a {{choice}} / {{filter}} with {{jsonpath("store.book.price >= 100")}} does
not match a book of price 100: the boundary value is routed the other way, with
no error.
The operators are also looked for inside quoted values, and {{in}} inside
words: {{store.book.title == 'Java in Action'}} is split at {{ in}} as well,
the parser gives up (more than one operator) and the text is evaluated as a
plain path, which fails with "Use bracket notion ['my prop'] if your property
contains blank characters". The same for a value with {{ size}}, {{ empty}}, {{
<}} ... in it.
*Reproduced* (camel-jsonpath, main): {{store.book.price <= 8.95}} and
{{$.store.book.price >= 8.95}} on {{cheap.json}} (one book of price 8.95) are
false; {{store.book.title == 'Java in Action'}} throws on a document with that
title.
*Fix*: {{getOperatorAtStart}} returns the longest operator the text starts with
(a word operator such as {{in}} only when a space or the end follows it), the
parser skips the operator and the one space after it (if any), and
{{EasyPredicateParser.tokens}} does not look for operators inside a single- or
double-quoted value. Predicates written with one space around a single operator
other than {{<=}} and {{>=}}, with no operator word in the value, are parsed as
before; a predicate without a space after the operator now keeps its value
whole ({{price <20}} gives {{$..*[?(@.price < 20)]}}).
*Tests*: {{EasyPredicateParserTest}} (three new methods: {{<=}}, {{>=}},
{{nin}}, no space after the operator, operator words inside quoted values, {{
index}} in a regex value) and a new {{EasyJsonPathComparisonOperatorsTest}} (a
choice with {{<=}} and {{>=}} on the boundary value, a title with {{in}},
matching and not matching) fail on main and pass with the fix.
*How it was found*: an OSS-Fuzz-style differential harness (random documents
and easy predicates evaluated through the jsonpath language vs the same
comparison in Java) run on HotSpot: of 50 000 random predicates (about half
numeric, half string equality), 426 {{<=}} / {{>=}} predicates that only a
price equal to the value satisfies were false, and 5 543 string predicates with
an operator word in the value threw; with the fix 200 000 inputs agree. A JVM
model in Rocq that executes the real class files states the operator choice as
kernel-checked theorems on the class files of main and of the fix
({{main_le_read_as_lt}}: {{ <= 10}} gives {{<}}, {{ >= 10}} gives {{>}}, {{
index}} gives {{in}}; {{fix_le_read_as_le}}); HotSpot gives the same results.
*Affected*: main, camel-4.22.x, camel-4.18.x, camel-4.14.x and camel-4.10.x
have the same {{getOperatorAtStart}} (read, not run); the easy syntax exists
since CAMEL-10702. The two production files of the fix apply to those branches
cleanly; the tests do not as is ({{EasyPredicateParserTest}} and the
{{$}}-rooted easy form come from CAMEL-24841).
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)