Skip to content

[Cases] Allow to add additional fields to IBM resilient connector#236144

Merged
janmonschke merged 36 commits intoelastic:mainfrom
janmonschke:cases/ibm-resilient-additional-fields
Oct 1, 2025
Merged

[Cases] Allow to add additional fields to IBM resilient connector#236144
janmonschke merged 36 commits intoelastic:mainfrom
janmonschke:cases/ibm-resilient-additional-fields

Conversation

@janmonschke
Copy link
Contributor

@janmonschke janmonschke commented Sep 23, 2025

Summary

Allows to send additional properties via the IBM resilient connector

Screenshot 2025-09-25 at 16 20 14 Screenshot 2025-09-25 at 16 20 37

Fixes #213890, Fixes #213896

How to test

  • Set up the IBM resilient connector and enable it
  • Create a new case and add {"test_text":"test"} to Additional fields
  • Save the case and check that the field exists in IBM resilient
  • Go back to the case in Kibana, update the additional fields, push the update and check that the new value is present in IBM resilient

(Advanced):

Try setting one of these values:

{
    "testing": "test",
    "test_text": "the text",
    "test_boolean": true,
    "test_number": 123,
    "test_date_picker": 2390748293,
    "test_date_time_picker": 2390748298,
    "test_select": 4,
    "test_multi_select": [1,3],
    "test_text_area": ""
}

Try setting test_select or test_multi_select. They are values that are validated on the server.

@janmonschke janmonschke self-assigned this Sep 23, 2025
@janmonschke janmonschke added release_note:enhancement backport:skip This PR does not require backporting Team:Cases Security Solution Cases team labels Sep 23, 2025
@janmonschke janmonschke marked this pull request as ready for review September 25, 2025 14:22
@janmonschke janmonschke requested review from a team as code owners September 25, 2025 14:22
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-cases (Team:Cases)

@janmonschke janmonschke changed the title [IN PROGRESS][Cases] Allow to add additional fields to IBM resilient connector Sep 25, 2025
if (action.schema) {
try {
action.schema.validate(subActionParams);
_subActionParams = action.schema.validate(subActionParams) as typeof subActionParams;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cnasikas This is needed in order to automatically transform the additionalFields string to an object that we can run validations on.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for fixing that. It makes sense to me.

@pmuellr
Copy link
Contributor

pmuellr commented Sep 25, 2025

Adding new parameters to a Connector typically involves creating an intermediate release, that just includes parameter schema changes. For more info: https://docs.elastic.dev/reops/developer-guide/best-practices-rules#upgrades-and-rollbacks . Note some of the docs only reference rule params, but connector params are affected here as well.

Typically folks will create a PR with JUST the schema changes, and anything else required for them, and nothing else. Get that merged, and running on Serverless. After it's running on Serverless, the rest of the PR can be merged. So there's typically ~ one week delay between these ...

@janmonschke
Copy link
Contributor Author

@pmuellr Could you comment on the pieces of code I'd need to put into a separate PR? Is it just the changes in x-pack/platform/plugins/shared/cases/common/types/domain/connector/v1.ts?

@janmonschke
Copy link
Contributor Author

@pmuellr looking at the slides you linked 👍 If I put the UI behind a feature flag, we should be good as well, right?

@pmuellr
Copy link
Contributor

pmuellr commented Sep 25, 2025

Could you comment on the pieces of code I'd need to put into a separate PR? Is it just the changes in x-pack/platform/plugins/shared/cases/common/types/domain/connector/v1.ts?

Correct. Though typically we don't modify "version" files like a v1.ts, but instead create a v2.ts. Not sure that's required in this case. @cnasikas ?

looking at the slides you linked 👍 If I put the UI behind a feature flag, we should be good as well, right?

Correct. Just more work, as you'll have to deal with the changing the feature flag in a later release to make it the default. :-)

enableCaseSummary: schema.boolean({ defaultValue: false }),
})
),
resilient: schema.object({
Copy link
Contributor

Choose a reason for hiding this comment

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

👌🏾 Thanks!

export const resilientFields = [
import type { ResilientFieldMeta } from './schema';

export const resilientFields: ResilientFieldMeta[] = [
Copy link
Contributor

Choose a reason for hiding this comment

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

👏🏾

givenValues,
null,
2
)}. Accepted values: ${valuesMeta.map((v) => `${v.value} (for "${v.label}")`)}`
Copy link
Contributor

Choose a reason for hiding this comment

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

Really nice error messaging here to get around the multi-select expectations. Thanks!

}
case 'datetimepicker':
case 'datepicker':
return isNumber(value) ? { date: value } : {};
Copy link
Contributor

Choose a reason for hiding this comment

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

Just confirming this is always expected to be number and doesn't need an additional isDate() conversion/check?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, this is supposed to be a number. Any other value will return a 400 from IBM Resilient

Copy link
Contributor

@michaelolo24 michaelolo24 left a comment

Choose a reason for hiding this comment

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

Nice work, thank you for getting this done so promptly!

read_only: schema.boolean(),
required: schema.nullable(schema.string()),
text: schema.string(),
internal: schema.boolean(),
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure if older versions of Resilient respond with this field. Should we make it optional (nullable) just to be safe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed in 2393254

}

// Custom fields need to be prefixed with 'properties.'
if (fieldMeta.prefix === 'properties') {
Copy link
Member

Choose a reason for hiding this comment

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

I would say not to make any assumptions about how users would put their custom fields. The IBM documentation is clear, so they should put the properties themselves. For example this is what they should put in the editor:

{
  "state":  41,
   "properties": {
       "foo": "bar"
    }
}
Copy link
Contributor Author

@janmonschke janmonschke Sep 30, 2025

Choose a reason for hiding this comment

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

imo, properties is an implementation detail and not necessarily known by the people that will use Kibana cases. I can change the logic to allow arbitrary prefixes if that sounds better?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 2393254 & 6dde18d

description?: { format: string; content: string };
incident_type_ids?: Array<{ id: number }>;
severity_code?: { id: number };
properties?: Record<string, unknown>;
Copy link
Member

Choose a reason for hiding this comment

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

We should remove this and add [unknown: string]: unknown, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, done

if (field === 'incidentTypes') {
if (isArray(value)) {
return { ids: value.map((item) => Number(item)) };
export function validateValues(
Copy link
Member

Choose a reason for hiding this comment

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

I am a bit concerned that we validate the values. What if an existing rule starts to fail because we started validating the fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If an invalid value is supplied, the request to IBM will fail anyways. This is just a way to enhance the editing experience, since customers will have to add id(s) and not labels.

Copy link
Member

@cnasikas cnasikas Oct 1, 2025

Choose a reason for hiding this comment

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

Are we sure that all IBM resilient versions behave the same? Maybe we can fail at everything new but not at the old/existing fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean only validate fields from the additionalFields?

Copy link
Member

Choose a reason for hiding this comment

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

I was thinking that, yes, to be sure that we do not introduce a breaking change. Maybe I am too cautious. Wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds sensible to me. Mind if I do that in a follow-up PR?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, ofc.

}

const fieldMeta = fieldsRecord[name];
if (!fieldMeta) {
Copy link
Member

Choose a reason for hiding this comment

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

I am a bit concerned that we validate the values. What if an existing rule starts to fail because we started validating here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If there is no metadata for that field, we cannot determine the required shape for the update request, which is why we rely on it here.

@elasticmachine
Copy link
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #16 / Endpoint plugin @ess @serverless @skipInServerlessMKI test metadata apis list endpoints GET route "after all" hook for "metadata api should return all hosts when filter is empty string"
  • [job] [logs] FTR Configs #32 / integrations When on the Trusted Apps list "after all" hook for "should be able to add a new trusted app and remove it"
  • [job] [logs] FTR Configs #99 / security APIs - Session Idle Session Idle cleanup should properly clean up session expired because of idle timeout when providers override global session config

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
cases 1173 1174 +1
stackConnectors 368 369 +1
total +2

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
cases 1.4MB 1.4MB +3.0KB
stackConnectors 714.0KB 722.7KB +8.7KB
total +11.7KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
cases 140.8KB 141.0KB +168.0B
stackConnectors 66.3KB 66.7KB +459.0B
total +627.0B

History

cc @janmonschke

Copy link
Member

@cnasikas cnasikas left a comment

Choose a reason for hiding this comment

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

LGTM! I tested and it is working as expected. My main concerns are:

  • Is throwing an error by validating the fields safe? I am concern about the old fields, not the new ones. Does all IBM resilient versions behave the same? Or was a case where some version did not throw an error for the old values?
  • About the custom fields and prefixing the properties, I do not think it is an implementation detail, because this is how the IBM Rest API docs tell you how to submit custom fields. Also, what if a custom field has the same key as a root field? Users will never be able to set both fields.
Copy link
Member

Choose a reason for hiding this comment

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

Could you please add some test to cover the new functionality?

@janmonschke janmonschke enabled auto-merge (squash) October 1, 2025 13:53
@janmonschke janmonschke added v9.2.0 backport:version Backport to applied version labels and removed backport:skip This PR does not require backporting labels Oct 1, 2025
@janmonschke janmonschke merged commit 76e6d95 into elastic:main Oct 1, 2025
17 checks passed
@kibanamachine kibanamachine added backport:skip This PR does not require backporting and removed backport:version Backport to applied version labels labels Oct 1, 2025
@jmikell821 jmikell821 added the Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t// label Oct 6, 2025
@elasticmachine
Copy link
Contributor

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

rylnd pushed a commit to rylnd/kibana that referenced this pull request Oct 17, 2025
…astic#236144)

## Summary

Allows to send additional properties via the IBM resilient connector

<img width="1252" height="355" alt="Screenshot 2025-09-25 at 16 20 14"
src="https://github.com/user-attachments/assets/78bbec79-22d2-47d5-8238-fcb14cfaf887"
/>
<img width="500" height="162" alt="Screenshot 2025-09-25 at 16 20 37"
src="https://github.com/user-attachments/assets/cd615bdb-648d-48a1-ade0-8c8db1977d01"
/>


Fixes elastic#213890, Fixes
elastic#213896

### How to test

- Set up the IBM resilient connector and enable it
- Create a new case and add `{"test_text":"test"}` to `Additional
fields`
- Save the case and check that the field exists in IBM resilient
- Go back to the case in Kibana, update the additional fields, push the
update and check that the new value is present in IBM resilient

**(Advanced)**:

Try setting one of these values:

```json
{
    "testing": "test",
    "test_text": "the text",
    "test_boolean": true,
    "test_number": 123,
    "test_date_picker": 2390748293,
    "test_date_time_picker": 2390748298,
    "test_select": 4,
    "test_multi_select": [1,3],
    "test_text_area": ""
}
```

Try setting `test_select` or `test_multi_select`. They are values that
are validated on the server.

---------

Co-authored-by: Michael Olorunnisola <michael.olorunnisola@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:enhancement Team:Cases Security Solution Cases team Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t// v9.2.0

9 participants