- Use ID token claims as the source of truth for Apple OAuth2 attributes
- Added Apple mapper type to OAuth2 client data validation
- Consolidated duplicated validation logic for BASIC, GITHUB, and APPLE mapper types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The lastCommit field was shared across all repository keys, causing
MissingObjectException when multiple repositories were registered.
When onUpdate fired for repo A it overwrote lastCommit, and subsequent
listFiles/getFileContent calls for repo B used repo A's commit whose
tree objects don't exist in repo B's object database.
Changed to a per-key Map<String, RevCommit> so each repository's
resolved commit is stored and retrieved independently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move TestDbCallbackExecutor from rule-engine test sources to
common/util main sources as DirectListeningExecutor, making it
available to all modules. Convert to an enum singleton since the
executor is stateless. Widen JpaAbstractDaoListeningExecutorService
service field type from JpaExecutorService to ListeningExecutor to
allow injecting DirectListeningExecutor in tests. Fix
AbstractChunkedAggregationTimeseriesDaoTest NPE by injecting the
direct executor into the spy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The stack-based check in DefaultTbContext.input() only catches a loop
on the second Kafka round-trip through the same rule chain. When the
target rule chain equals the node's own rule chain (direct self-loop),
the first iteration is always unnecessary and should be rejected
immediately before any enqueue occurs.
Add an eager check in TbRuleChainInputNode.onMsg(): if the resolved
targetRuleChainId equals ctx.getSelf().getRuleChainId() (the rule chain
that contains this node), tellFailure() is called right away.
Together with the existing stack-based check in DefaultTbContext.input()
this forms a two-layer defence:
- Layer 1 (TbRuleChainInputNode): direct loops A→A, caught immediately
- Layer 2 (DefaultTbContext): indirect cycles A→B→A, caught on second pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a TbRuleChainInputNode has `forwardMsgToDefaultRuleChain=true` and the originator's
default rule chain is the same as the rule chain containing this node, the message enters
an infinite loop: the node forwards to the default rule chain, which routes back to the
same node, which forwards again, causing unbounded recursion and 100% CPU on rule-engine.
Fix: detect the loop in DefaultTbContext.input() by checking whether the calling rule node
is already present in the message's return stack (TbMsgProcessingCtx). On the second+
iteration the stack already contains the (ruleChainId, ruleNodeId) pair of the node,
so the call is a cycle. In that case tellFailure() is called with a descriptive message
and a WARN log is emitted instead of re-enqueuing the message.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>