[8.8] [Detection Engine][Exceptions] - Fix exception item update route (#159223) (#159420)

# Backport

This will backport the following commits from `main` to `8.8`:
- [[Detection Engine][Exceptions] - Fix exception item update route
(#159223)](https://github.com/elastic/kibana/pull/159223)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Yara
Tercero","email":"yctercero@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-06-09T19:31:03Z","message":"[Detection
Engine][Exceptions] - Fix exception item update route (#159223)\n\n##
Summary\r\n\r\nAddresses issue
159230","sha":"f895c5c2058f3f36c828fe9d8f1dbc0c19a2b381","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:fix","Team:
SecuritySolution","Feature:Rule
Exceptions","v8.7.2","v8.9.0","Team:Detection
Engine","v8.8.2"],"number":159223,"url":"https://github.com/elastic/kibana/pull/159223","mergeCommit":{"message":"[Detection
Engine][Exceptions] - Fix exception item update route (#159223)\n\n##
Summary\r\n\r\nAddresses issue
159230","sha":"f895c5c2058f3f36c828fe9d8f1dbc0c19a2b381"}},"sourceBranch":"main","suggestedTargetBranches":["8.7","8.8"],"targetPullRequestStates":[{"branch":"8.7","label":"v8.7.2","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/159223","number":159223,"mergeCommit":{"message":"[Detection
Engine][Exceptions] - Fix exception item update route (#159223)\n\n##
Summary\r\n\r\nAddresses issue
159230","sha":"f895c5c2058f3f36c828fe9d8f1dbc0c19a2b381"}},{"branch":"8.8","label":"v8.8.2","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Yara Tercero <yctercero@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2023-06-21 11:57:59 -04:00 committed by GitHub
parent ed6bbd56da
commit d861400833
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 198 additions and 5 deletions

View file

@ -9,7 +9,7 @@
"operator": "included"
}
],
"item_id": "993f43f7-325d-4df3-9338-964e77c37053",
"item_id": "simple_list_item",
"name": "Test comments - exception list item",
"namespace_type": "single",
"tags": [],

View file

@ -59,7 +59,7 @@ export const updateOverwriteExceptionListItem = async ({
entries,
expire_time: expireTime,
immutable: undefined,
item_id: itemId,
item_id: itemId ?? exceptionListItem.item_id,
list_id: exceptionListItem.list_id,
list_type: 'item',
meta,
@ -72,7 +72,7 @@ export const updateOverwriteExceptionListItem = async ({
version: exceptionListItem._version ? parseInt(exceptionListItem._version, 10) : undefined,
},
{
id,
id: id ?? exceptionListItem.id,
overwrite: true,
version: _version,
}

View file

@ -13,12 +13,19 @@ import type {
} from '@kbn/securitysolution-io-ts-list-types';
import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants';
import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock';
import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock';
import {
getCreateExceptionListItemMinimalSchemaMock,
getCreateExceptionListItemSchemaMock,
} from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock';
import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock';
import { getUpdateMinimalExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_exception_list_item_schema.mock';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils';
import {
deleteAllExceptions,
removeExceptionListItemServerGeneratedProperties,
removeExceptionListServerGeneratedProperties,
} from '../../utils';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
@ -31,6 +38,192 @@ export default ({ getService }: FtrProviderContext) => {
await deleteAllExceptions(supertest, log);
});
describe('regressions', () => {
it('updates an item via its item_id without side effects', async () => {
// create a simple exception list
await supertest
.post(EXCEPTION_LIST_URL)
.set('kbn-xsrf', 'true')
.send(getCreateExceptionListMinimalSchemaMock())
.expect(200);
// create a simple exception list item
await supertest
.post(EXCEPTION_LIST_ITEM_URL)
.set('kbn-xsrf', 'true')
.send(getCreateExceptionListItemMinimalSchemaMock())
.expect(200);
const { body: items } = await supertest
.get(
`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${
getCreateExceptionListMinimalSchemaMock().list_id
}`
)
.set('kbn-xsrf', 'true')
.send()
.expect(200);
expect(items.total).to.eql(1);
const [item] = items.data;
const expectedId = item.id;
const expectedItemId = item.item_id;
// update an exception list item's name, specifying its item_id
const updatePayload: UpdateExceptionListItemSchema = {
...getUpdateMinimalExceptionListItemSchemaMock(),
name: 'some other name',
};
await supertest
.put(EXCEPTION_LIST_ITEM_URL)
.set('kbn-xsrf', 'true')
.send(updatePayload)
.expect(200);
const { body: itemsAfterUpdate } = await supertest
.get(
`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${
getCreateExceptionListMinimalSchemaMock().list_id
}`
)
.set('kbn-xsrf', 'true')
.send()
.expect(200);
// Validate that we have a single exception item with the expected properties
expect(itemsAfterUpdate.total).to.eql(1);
const [updatedItem] = itemsAfterUpdate.data;
expect(updatedItem.name).to.eql('some other name');
expect(updatedItem.id?.length).to.be.greaterThan(0);
expect(updatedItem.id).to.equal(expectedId);
expect(updatedItem.item_id?.length).to.be.greaterThan(0);
expect(updatedItem.item_id).to.equal(expectedItemId);
});
it('updates an item via its id without side effects', async () => {
// create a simple exception list
await supertest
.post(EXCEPTION_LIST_URL)
.set('kbn-xsrf', 'true')
.send(getCreateExceptionListMinimalSchemaMock())
.expect(200);
// create a simple exception list item
await supertest
.post(EXCEPTION_LIST_ITEM_URL)
.set('kbn-xsrf', 'true')
.send(getCreateExceptionListItemMinimalSchemaMock())
.expect(200);
const { body: items } = await supertest
.get(
`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${
getCreateExceptionListMinimalSchemaMock().list_id
}`
)
.set('kbn-xsrf', 'true')
.send()
.expect(200);
expect(items.total).to.eql(1);
const [item] = items.data;
const expectedId = item.id;
const expectedItemId = item.item_id;
// update an exception list item's name, specifying its id
const { item_id: _, ...updateItemWithoutItemId } =
getUpdateMinimalExceptionListItemSchemaMock();
const updatePayload: UpdateExceptionListItemSchema = {
...updateItemWithoutItemId,
name: 'some other name',
id: expectedId,
};
await supertest
.put(EXCEPTION_LIST_ITEM_URL)
.set('kbn-xsrf', 'true')
.send(updatePayload)
.expect(200);
const { body: itemsAfterUpdate } = await supertest
.get(
`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${
getCreateExceptionListMinimalSchemaMock().list_id
}`
)
.set('kbn-xsrf', 'true')
.send()
.expect(200);
// Validate that we have a single exception item with the expected properties
expect(itemsAfterUpdate.total).to.eql(1);
const [updatedItem] = itemsAfterUpdate.data;
expect(updatedItem.name).to.eql('some other name');
expect(updatedItem.id?.length).to.be.greaterThan(0);
expect(updatedItem.id).to.equal(expectedId);
expect(updatedItem.item_id?.length).to.be.greaterThan(0);
expect(updatedItem.item_id).to.equal(expectedItemId);
});
it('preserves optional fields that are unspecified in the request, a la PATCH semantics', async () => {
// create a simple exception list
await supertest
.post(EXCEPTION_LIST_URL)
.set('kbn-xsrf', 'true')
.send(getCreateExceptionListMinimalSchemaMock())
.expect(200);
// create a simple exception list item
const { meta, ...createPayload } = {
...getCreateExceptionListItemSchemaMock(),
comments: [
{
comment: 'Im an old comment',
},
],
};
await supertest
.post(EXCEPTION_LIST_ITEM_URL)
.set('kbn-xsrf', 'true')
.send(createPayload)
.expect(200);
const { body: items } = await supertest
.get(`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${createPayload.list_id}`)
.set('kbn-xsrf', 'true')
.send()
.expect(200);
expect(items.total).to.eql(1);
const [item] = items.data;
// Perform an update with only required fields. If any fields change on the item, then they're not really optional.
const { item_id: _, ...updatePayload } = {
...getUpdateMinimalExceptionListItemSchemaMock(),
id: item.id,
};
await supertest
.put(EXCEPTION_LIST_ITEM_URL)
.set('kbn-xsrf', 'true')
.send(updatePayload)
.expect(200);
const { body: itemsAfterUpdate } = await supertest
.get(`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${createPayload.list_id}`)
.set('kbn-xsrf', 'true')
.send()
.expect(200);
// Validate that we have a single exception item with the expected properties
expect(itemsAfterUpdate.total).to.eql(1);
const [updatedItem] = itemsAfterUpdate.data;
expect(updatedItem.id).to.eql(item.id);
expect(removeExceptionListItemServerGeneratedProperties(updatedItem)).to.eql(
removeExceptionListItemServerGeneratedProperties(item)
);
});
});
it('should update a single exception list item property of name using an id', async () => {
// create a simple exception list
await supertest