Federico Mariani created CAMEL-24160:
----------------------------------------
Summary: camel-salesforce - Umbrella: high-severity findings from
July 2026 review (auth, streaming/pubsub, REST/bulk/composite)
Key: CAMEL-24160
URL: https://issues.apache.org/jira/browse/CAMEL-24160
Project: Camel
Issue Type: Bug
Components: camel-salesforce
Reporter: Federico Mariani
Attachments: camel-salesforce-review-2026-07.md
Umbrella for the high-severity findings of a deep code review of
camel-salesforce-component on main (4.22.0-SNAPSHOT). The full findings
document is attached. External behavior was verified against decompiled jars
(Jetty 12.1.11, CometD 9.0.1, grpc-api 1.82.2). The critical finding
(streamQueryResult iterator hanging the route thread forever on queryMore
failure) is tracked separately with a failing reproducer test. Individual
findings can be split out into their own issues as they are picked up.
*Auth / session / HTTP client*
# {{SalesforceSecurityHandler:176,181,218}} — 401 handling unconditionally
dereferences the nullable conversation client attribute; CometD streaming
requests (no attribute) NPE inside the listener, so handler-level transparent
re-login for streaming is dead (regression from CAMEL-17346; transport stalls
until maxNetworkDelay).
# {{SalesforceSession:112-131}} — attemptLoginUntilSuccessful latch race: the
winning thread replaces the already-counted-down latch only after the CAS, so
concurrent waiters proceed with the stale token on every login cycle after the
first (code carries a "TODO: This is janky").
*Streaming (CometD) / Pub/Sub (gRPC)*
# {{SubscriptionHelper:147-149}} — handshake failures retry in a tight loop
({{client.handshake()}} immediately, no backoff, no maxBackoff abort —
machinery exists but is only applied to subscription failures; pre-rewrite code
had it).
# {{PubSubApiClient:341-344}} — onError logs trailers via
{{Metadata.Key.of(name, ASCII_STRING_MARSHALLER)}}, which throws
IllegalArgumentException for {{-bin}} keys (e.g. standard
{{grpc-status-details-bin}}) before resubscribeOnError() is reached —
reconnection permanently dead, no exception-handler notification.
# {{PubSubApiClient:380-398}} — resubscribeOnError() has no stop/channel-state
check; a stop racing an in-flight error loops forever (UNAVAILABLE -> sleep ->
resubscribe) on a gRPC callback thread.
*REST / Bulk / Composite processors*
# {{SalesforceEndpointConfig.toValueMap}} — the documented {{allOrNone}} URI
option is never put into the endpoint config map, so it can never take effect;
batches lose the requested atomicity silently (only the header works).
# {{DefaultBulkApiV2Client:111-125,235-249}} —
changeJobState/changeQueryJobState error branch is missing a return, invoking
the AsyncCallback twice; a 400 on bulk2CloseJob/AbortJob makes the remainder of
the route execute twice for one input.
# {{JsonRestProcessor:202-260}} — deferred SObject-type detection: when no
"type" property is found (zero-record query, aggregate query, apexCall), the
resulting RuntimeException escapes the IOException-only catch,
callback.done(false) still runs without setting an exception, and the exchange
completes *successfully* with the request body as the "result".
# {{JsonRestProcessor:244}} — {{while (parser.nextToken() != END_OBJECT)}}
never terminates for non-object JSON (bare scalar/array); a Jetty worker thread
spins at 100% CPU forever and the exchange never completes (apexCall with
deferred detection).
_This issue was researched and filed by Claude Code (AI) on behalf of Federico
Mariani (fmariani). Full findings document from the review is attached to the
umbrella issues._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)