Skip to content

feat: building block hardening - #868

Open
mbritense wants to merge 4 commits into
next-minorfrom
feature/793-building-block-hardening
Open

feat: building block hardening#868
mbritense wants to merge 4 commits into
next-minorfrom
feature/793-building-block-hardening

Conversation

@mbritense

Copy link
Copy Markdown
Contributor
  • Building block call activities are validated on save, update, and at runtime: a missing, wrong, or namespace-shadowed business key mapping now fails with a clear fix-it message instead of the building block silently running against the wrong case data
  • The validation understands engine namespace rules: a correct camunda:in that is ignored because operaton:in elements are present is detected and explained
  • Deploying a new process version with a broken building block call activity logs an error pointing at the problem
  • Input mappings must target building block fields and output mappings must read from them; invalid mappings are rejected on save instead of silently ignored
  • Plugin action properties that resolve to no value are logged with property, activity, and process, making silent misbehaviour (e.g. mails without attachments) diagnosable
  • Regression tests prove passing values and file references into a building block, resolving them in plugin actions, and prefilling task forms from the building block document
  • Documentation added on how data and file attachments reach a building block and what the call activity must look like
  • Release notes for 13.40.0 filled in

@mbritense
mbritense requested review from a team as code owners July 30, 2026 11:03
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@mbritense, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 58949e88-ceaa-4f18-b615-e622b5fc598a

📥 Commits

Reviewing files that changed from the base of the PR and between b4cb0d3 and 2b17794.

📒 Files selected for processing (3)
  • backend/building-block/src/main/kotlin/com/ritense/buildingblock/processlink/mapper/BuildingBlockProcessLinkMapper.kt
  • backend/plugin/src/main/kotlin/com/ritense/plugin/service/PluginService.kt
  • documentation/release-notes/13.x.x/13.41.0/README.md
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added validation for building block call-activity business keys during configuration and execution, with clearer error messages.
    • Enforced valid building block input and output mappings.
    • Added support for passing attachment references into building blocks.
    • Added warnings when plugin action properties cannot be resolved.
  • Documentation

    • Expanded guidance on building block data mapping, attachment handling, and call-activity requirements.
  • Bug Fixes

    • Improved reliability of building block process-link validation during redeployment.

Walkthrough

Building-block process links now validate doc: mapping prefixes and call-activity business-key mappings during creation, update, execution, and BPMN redeployment. Runtime input and output handling skips unsupported mappings with warnings. Plugin action resolution logs unresolved properties. Tests and BPMN fixtures cover namespace conflicts, attachments, plugin inputs, form prefill, and failure cases. Documentation and release notes describe the updated data flow and attachment handling.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/793-building-block-hardening

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/plugin/src/main/kotlin/com/ritense/plugin/service/PluginService.kt (1)

636-656: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Log unresolved action properties also when they are omitted from the resolver result.

ValueResolverServiceImpl states that “An unresolved requestedValue will not be included in the returned map,” but logUnresolvedActionProperties only flags values whose key is present and mapped to null. Add the missing keys to the warning path so pv: references that fail to resolve are reported instead of being silently handled as literals.

🧹 Nitpick comments (1)
backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockCallActivityListenerIT.kt (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate the duplicated process-definition lookup helper.

Three test classes each add a private helper that performs the exact same RepositoryService query (by key, latest version, throw if not deployed), just under different names/signatures. Since all three extend BaseIntegrationTest, moving this to that shared base (or a small test utility) avoids drift as more fixtures are added.

  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockCallActivityListenerIT.kt#L375-382: move processDefinitionId(processKey: String = MAIN_PROCESS_KEY) to BaseIntegrationTest and remove the local copy.
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/mapper/BuildingBlockProcessLinkIntegrationTest.kt#L412-419: replace latestProcessDefinitionId(processKey) with a call to the shared helper.
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockFormPrefillIT.kt#L137-144: replace processDefinitionId(processKey) with a call to the shared helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e1e6b5d-99e7-45c3-8877-99610d0ce72e

📥 Commits

Reviewing files that changed from the base of the PR and between f7e21ce and b4cb0d3.

📒 Files selected for processing (22)
  • .gitignore
  • backend/building-block/src/main/kotlin/com/ritense/buildingblock/configuration/BuildingBlockAutoConfiguration.kt
  • backend/building-block/src/main/kotlin/com/ritense/buildingblock/processlink/mapper/BuildingBlockProcessLinkMapper.kt
  • backend/building-block/src/main/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockCallActivityBusinessKeyValidator.kt
  • backend/building-block/src/main/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockCallActivityListener.kt
  • backend/building-block/src/main/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockProcessLinkCopyValidator.kt
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/TestApplication.kt
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/TestMailPlugin.kt
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/TestMailPluginFactory.kt
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/mapper/BuildingBlockProcessLinkIntegrationTest.kt
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockCallActivityBusinessKeyValidatorTest.kt
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockCallActivityListenerIT.kt
  • backend/building-block/src/test/kotlin/com/ritense/buildingblock/processlink/service/BuildingBlockFormPrefillIT.kt
  • backend/building-block/src/test/resources/config/building-block/bezwaar/1-0-0/bpmn/building-block-process.bpmn
  • backend/building-block/src/test/resources/config/building-block/bezwaar/1-0-0/document/definition/bezwaar.schema.document-definition.json
  • backend/building-block/src/test/resources/config/case/bb-case/1-0-0/bpmn/building-block-call-activity-main-dual-ns.bpmn
  • backend/building-block/src/test/resources/config/case/bb-case/1-0-0/bpmn/building-block-call-activity-main-wrong-key.bpmn
  • backend/building-block/src/test/resources/config/case/bb-case/1-0-0/document/definition/bb-case.schema.document-definition.json
  • backend/building-block/src/test/resources/config/plugin/test-mail.pluginconfig.json
  • backend/plugin/src/main/kotlin/com/ritense/plugin/service/PluginService.kt
  • documentation/features/building-blocks/README.md
  • documentation/release-notes/13.x.x/13.40.0/README.md

Comment on lines +39 to +67
@EventListener(ProcessLinksCopiedEvent::class)
fun validateCopiedBuildingBlockLinks(event: ProcessLinksCopiedEvent) {
val buildingBlockLinks = event.copiedProcessLinks.filterIsInstance<BuildingBlockProcessLink>()
if (buildingBlockLinks.isEmpty()) {
return
}
val bpmnModel = repositoryService.getBpmnModelInstance(event.processDefinitionId) ?: return

buildingBlockLinks.forEach { link ->
val callActivity = bpmnModel.getModelElementById<CallActivity>(link.activityId)
if (callActivity == null) {
logger.error {
"Building block process link '${link.id}' was copied to process definition " +
"'${event.processDefinitionId}', but activity '${link.activityId}' is not a call " +
"activity in that definition. The building block cannot start from this definition."
}
return@forEach
}
try {
BuildingBlockCallActivityBusinessKeyValidator.validate(callActivity, event.processDefinitionId)
} catch (e: IllegalStateException) {
logger.error {
"Building block process link '${link.id}' was copied to a process definition with an " +
"invalid call activity configuration. The building block will fail to start until " +
"the BPMN is fixed. ${e.message}"
}
}
}
}

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Broaden the catch to actually guarantee "never fails deployment."

The class doc states it must never fail deployment, but only IllegalStateException is caught around BuildingBlockCallActivityBusinessKeyValidator.validate. Any other unexpected exception (e.g. from unforeseen DOM/BPMN model issues) would propagate through the @EventListener and could break redeployment — contradicting the documented invariant.

🛡️ Proposed fix to widen the safety net
             try {
                 BuildingBlockCallActivityBusinessKeyValidator.validate(callActivity, event.processDefinitionId)
-            } catch (e: IllegalStateException) {
+            } catch (e: Exception) {
                 logger.error {
                     "Building block process link '${link.id}' was copied to a process definition with an " +
                         "invalid call activity configuration. The building block will fail to start until " +
                         "the BPMN is fixed. ${e.message}"
                 }
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@EventListener(ProcessLinksCopiedEvent::class)
fun validateCopiedBuildingBlockLinks(event: ProcessLinksCopiedEvent) {
val buildingBlockLinks = event.copiedProcessLinks.filterIsInstance<BuildingBlockProcessLink>()
if (buildingBlockLinks.isEmpty()) {
return
}
val bpmnModel = repositoryService.getBpmnModelInstance(event.processDefinitionId) ?: return
buildingBlockLinks.forEach { link ->
val callActivity = bpmnModel.getModelElementById<CallActivity>(link.activityId)
if (callActivity == null) {
logger.error {
"Building block process link '${link.id}' was copied to process definition " +
"'${event.processDefinitionId}', but activity '${link.activityId}' is not a call " +
"activity in that definition. The building block cannot start from this definition."
}
return@forEach
}
try {
BuildingBlockCallActivityBusinessKeyValidator.validate(callActivity, event.processDefinitionId)
} catch (e: IllegalStateException) {
logger.error {
"Building block process link '${link.id}' was copied to a process definition with an " +
"invalid call activity configuration. The building block will fail to start until " +
"the BPMN is fixed. ${e.message}"
}
}
}
}
`@EventListener`(ProcessLinksCopiedEvent::class)
fun validateCopiedBuildingBlockLinks(event: ProcessLinksCopiedEvent) {
val buildingBlockLinks = event.copiedProcessLinks.filterIsInstance<BuildingBlockProcessLink>()
if (buildingBlockLinks.isEmpty()) {
return
}
val bpmnModel = repositoryService.getBpmnModelInstance(event.processDefinitionId) ?: return
buildingBlockLinks.forEach { link ->
val callActivity = bpmnModel.getModelElementById<CallActivity>(link.activityId)
if (callActivity == null) {
logger.error {
"Building block process link '${link.id}' was copied to a process definition " +
"'${event.processDefinitionId}', but activity '${link.activityId}' is not a call " +
"activity in that definition. The building block cannot start from this definition."
}
return@forEach
}
try {
BuildingBlockCallActivityBusinessKeyValidator.validate(callActivity, event.processDefinitionId)
} catch (e: Exception) {
logger.error {
"Building block process link '${link.id}' was copied to a process definition with an " +
"invalid call activity configuration. The building block will fail to start until " +
"the BPMN is fixed. ${e.message}"
}
}
}
}

Comment thread documentation/release-notes/13.x.x/13.40.0/README.md Outdated
require(invalidInputTargets.isEmpty()) {
"Input mapping targets must be building block fields. A value passed to a building block is " +
"stored in the building block document and can be referenced inside the building block " +
"with 'doc:'. Invalid targets: ${invalidInputTargets.joinToString()}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

That's a lot of words! I don't think this is a showstopper or anything, but if you have the chance, can you make this a bit less wordy? This applies to the other require as well


* New bugfix.

## Documentation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This isn't a section for the release notes. We link to relevant release notes on the individual release notes. I see the purpose of it, though, so maybe link it in the "Clearer rules for building block input and output mappings", or one of the other ones you added?

* variable (pv:) inside a building block: values passed to a building block only exist in the
* building block document (doc:), never as process variables.
*/
private fun logUnresolvedActionProperties(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure i like this. i think there can be valid cases where some data is null. if every times that is logged as warn this might cause all kinds of spam. I would either remove this, or change the log level to debug.

* **Building block call activities are now validated**

New enhancement explanation.
The business key configuration of a building block call activity is checked when the building block link is saved

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I feel that some of these release notes go too much into the technical detail. They should be easily understandable and preferably not too long.

@ivo-ritense ivo-ritense added the test env Create a remote test environment for this PR in the Ritense product development cluster label Aug 11, 2026
@valtimo-platform

valtimo-platform Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Will create a test environment. This comment will be updated once it is available. This usually takes a few minutes.
Closing or merging this PR will automatically delete the test environment. Pushing commits to this PR will update the test environment.
Progress:

  • Created test environment
  • Images tagged testEnv.pr868_commit.35dede91be_contents.29ad4da0e7_build.652 (frontend) / testEnv.pr868_commit.2b17794ee2_contents.1018741c0c_build.1974 (backend) available
  • Started test environment
  • Test environment is running at https://pr868.product-development.test.k8s.ritense.com

Test environment metadata:

  • URL: https://pr868.product-development.test.k8s.ritense.com
  • Commit: 2b17794
  • Frontend contents: 29ad4da0e7
  • Backend contents: 1018741c0c
  • Frontend image: ghcr.io/valtimo-platform/valtimo/gzac-frontend:testEnv.pr868_commit.35dede91be_contents.29ad4da0e7_build.652
  • Backend image: ghcr.io/valtimo-platform/valtimo/gzac-backend:testEnv.pr868_commit.2b17794ee2_contents.1018741c0c_build.1974

Observability:

@ivo-ritense

Copy link
Copy Markdown
Collaborator

Validation works for business key and input mappings when saving a process, but the feedback is in the console instead of to the user.

@ivo-ritense ivo-ritense added tested and removed test env Create a remote test environment for this PR in the Ritense product development cluster labels Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants