diff --git a/x-pack/plugins/cases/server/plugin.ts b/x-pack/plugins/cases/server/plugin.ts index bb1be163585a8..c04e495889a74 100644 --- a/x-pack/plugins/cases/server/plugin.ts +++ b/x-pack/plugins/cases/server/plugin.ts @@ -21,7 +21,7 @@ import { createCaseCommentSavedObjectType, caseConfigureSavedObjectType, caseConnectorMappingsSavedObjectType, - caseSavedObjectType, + createCaseSavedObjectType, caseUserActionSavedObjectType, subCaseSavedObjectType, } from './saved_object_types'; @@ -94,7 +94,7 @@ export class CasePlugin { ); core.savedObjects.registerType(caseConfigureSavedObjectType); core.savedObjects.registerType(caseConnectorMappingsSavedObjectType); - core.savedObjects.registerType(caseSavedObjectType); + core.savedObjects.registerType(createCaseSavedObjectType(core, this.log)); core.savedObjects.registerType(caseUserActionSavedObjectType); this.log.debug( diff --git a/x-pack/plugins/cases/server/saved_object_types/cases.ts b/x-pack/plugins/cases/server/saved_object_types/cases.ts index 199017c36fa3e..a362d77c06626 100644 --- a/x-pack/plugins/cases/server/saved_object_types/cases.ts +++ b/x-pack/plugins/cases/server/saved_object_types/cases.ts @@ -5,11 +5,22 @@ * 2.0. */ -import { SavedObjectsType } from 'src/core/server'; +import { + CoreSetup, + Logger, + SavedObject, + SavedObjectsExportTransformContext, + SavedObjectsType, +} from 'src/core/server'; import { CASE_SAVED_OBJECT } from '../../common'; +import { ESCaseAttributes } from '../services/cases/types'; +import { handleExport } from './import_export/export'; import { caseMigrations } from './migrations'; -export const caseSavedObjectType: SavedObjectsType = { +export const createCaseSavedObjectType = ( + coreSetup: CoreSetup, + logger: Logger +): SavedObjectsType => ({ name: CASE_SAVED_OBJECT, hidden: true, namespaceType: 'single', @@ -144,4 +155,14 @@ export const caseSavedObjectType: SavedObjectsType = { }, }, migrations: caseMigrations, -}; + management: { + importableAndExportable: true, + defaultSearchField: 'title', + icon: 'folderExclamation', + getTitle: (savedObject: SavedObject) => savedObject.attributes.title, + onExport: async ( + context: SavedObjectsExportTransformContext, + objects: Array> + ) => handleExport({ context, objects, coreSetup, logger }), + }, +}); diff --git a/x-pack/plugins/cases/server/saved_object_types/comments.ts b/x-pack/plugins/cases/server/saved_object_types/comments.ts index 00985df8ab834..af14123eca580 100644 --- a/x-pack/plugins/cases/server/saved_object_types/comments.ts +++ b/x-pack/plugins/cases/server/saved_object_types/comments.ts @@ -109,5 +109,8 @@ export const createCaseCommentSavedObjectType = ({ }, }, }, - migrations: () => createCommentsMigrations(migrationDeps), + migrations: createCommentsMigrations(migrationDeps), + management: { + importableAndExportable: true, + }, }); diff --git a/x-pack/plugins/cases/server/saved_object_types/import_export/export.ts b/x-pack/plugins/cases/server/saved_object_types/import_export/export.ts new file mode 100644 index 0000000000000..d089079314443 --- /dev/null +++ b/x-pack/plugins/cases/server/saved_object_types/import_export/export.ts @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + CoreSetup, + Logger, + SavedObject, + SavedObjectsClientContract, + SavedObjectsExportTransformContext, +} from 'kibana/server'; +import { + CaseUserActionAttributes, + CASE_COMMENT_SAVED_OBJECT, + CASE_SAVED_OBJECT, + CASE_USER_ACTION_SAVED_OBJECT, + CommentAttributes, + MAX_DOCS_PER_PAGE, + SAVED_OBJECT_TYPES, +} from '../../../common'; +import { createCaseError, defaultSortField } from '../../common'; +import { ESCaseAttributes } from '../../services/cases/types'; + +export async function handleExport({ + context, + objects, + coreSetup, + logger, +}: { + context: SavedObjectsExportTransformContext; + objects: Array>; + coreSetup: CoreSetup; + logger: Logger; +}): Promise>> { + try { + if (objects.length <= 0) { + return []; + } + + const [{ savedObjects }] = await coreSetup.getStartServices(); + const savedObjectsClient = savedObjects.getScopedClient(context.request, { + includedHiddenTypes: SAVED_OBJECT_TYPES, + }); + + const caseIds = objects.map((caseObject) => caseObject.id); + const attachmentsAndUserActionsForCases = await getAttachmentsAndUserActionsForCases( + savedObjectsClient, + caseIds + ); + + return [...objects, ...attachmentsAndUserActionsForCases.flat()]; + } catch (error) { + throw createCaseError({ + message: `Failed to retrieve associated objects for exporting of cases: ${error}`, + error, + logger, + }); + } +} + +async function getAttachmentsAndUserActionsForCases( + savedObjectsClient: SavedObjectsClientContract, + caseIds: string[] +): Promise>> { + const [attachments, userActions] = await Promise.all([ + getAssociatedObjects({ + savedObjectsClient, + caseIds, + sortField: defaultSortField, + type: CASE_COMMENT_SAVED_OBJECT, + }), + getAssociatedObjects({ + savedObjectsClient, + caseIds, + sortField: 'action_at', + type: CASE_USER_ACTION_SAVED_OBJECT, + }), + ]); + + return [...attachments, ...userActions]; +} + +async function getAssociatedObjects({ + savedObjectsClient, + caseIds, + sortField, + type, +}: { + savedObjectsClient: SavedObjectsClientContract; + caseIds: string[]; + sortField: string; + type: string; +}): Promise>> { + const references = caseIds.map((id) => ({ type: CASE_SAVED_OBJECT, id })); + + const finder = savedObjectsClient.createPointInTimeFinder({ + type, + hasReferenceOperator: 'OR', + hasReference: references, + perPage: MAX_DOCS_PER_PAGE, + sortField, + sortOrder: 'asc', + }); + + let result: Array> = []; + for await (const findResults of finder.find()) { + result = result.concat(findResults.saved_objects); + } + + return result; +} diff --git a/x-pack/plugins/cases/server/saved_object_types/index.ts b/x-pack/plugins/cases/server/saved_object_types/index.ts index 2c39a10f61da7..f6b87d1d480c1 100644 --- a/x-pack/plugins/cases/server/saved_object_types/index.ts +++ b/x-pack/plugins/cases/server/saved_object_types/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -export { caseSavedObjectType } from './cases'; +export { createCaseSavedObjectType } from './cases'; export { subCaseSavedObjectType } from './sub_case'; export { caseConfigureSavedObjectType } from './configure'; export { createCaseCommentSavedObjectType } from './comments'; diff --git a/x-pack/plugins/cases/server/saved_object_types/user_actions.ts b/x-pack/plugins/cases/server/saved_object_types/user_actions.ts index 16bb7ac09a6ef..883105982bcb3 100644 --- a/x-pack/plugins/cases/server/saved_object_types/user_actions.ts +++ b/x-pack/plugins/cases/server/saved_object_types/user_actions.ts @@ -49,4 +49,7 @@ export const caseUserActionSavedObjectType: SavedObjectsType = { }, }, migrations: userActionsMigrations, + management: { + importableAndExportable: true, + }, }; diff --git a/x-pack/test/case_api_integration/common/fixtures/saved_object_exports/single_case_user_actions_one_comment.ndjson b/x-pack/test/case_api_integration/common/fixtures/saved_object_exports/single_case_user_actions_one_comment.ndjson new file mode 100644 index 0000000000000..2fb02f297c6ea --- /dev/null +++ b/x-pack/test/case_api_integration/common/fixtures/saved_object_exports/single_case_user_actions_one_comment.ndjson @@ -0,0 +1,5 @@ +{"attributes":{"closed_at":null,"closed_by":null,"connector":{"fields":[],"name":"none","type":".none"},"created_at":"2021-08-26T19:48:01.292Z","created_by":{"email":null,"full_name":null,"username":"elastic"},"description":"a description","external_service":null,"owner":"securitySolution","settings":{"syncAlerts":true},"status":"open","tags":["some tags"],"title":"A case to export","type":"individual","updated_at":"2021-08-26T19:48:30.151Z","updated_by":{"email":null,"full_name":null,"username":"elastic"}},"coreMigrationVersion":"8.0.0","id":"85541260-06a6-11ec-b3f9-3d05c48a7d46","migrationVersion":{"cases":"7.15.0"},"references":[],"type":"cases","updated_at":"2021-08-26T19:48:30.162Z","version":"WzM0NDEsMV0="} +{"attributes":{"action":"create","action_at":"2021-08-26T19:48:01.292Z","action_by":{"email":null,"full_name":null,"username":"elastic"},"action_field":["description","status","tags","title","connector","settings","owner"],"new_value":"{\"type\":\"individual\",\"title\":\"A case to export\",\"tags\":[\"some tags\"],\"description\":\"a description\",\"connector\":{\"id\":\"none\",\"name\":\"none\",\"type\":\".none\",\"fields\":null},\"settings\":{\"syncAlerts\":true},\"owner\":\"securitySolution\"}","old_value":null,"owner":"securitySolution"},"coreMigrationVersion":"8.0.0","id":"8cb85070-06a6-11ec-b3f9-3d05c48a7d46","migrationVersion":{"cases-user-actions":"7.14.0"},"references":[{"id":"85541260-06a6-11ec-b3f9-3d05c48a7d46","name":"associated-cases","type":"cases"}],"score":null,"sort":[1630007281292,7288],"type":"cases-user-actions","updated_at":"2021-08-26T19:48:13.687Z","version":"WzIzODIsMV0="} +{"attributes":{"associationType":"case","comment":"A comment for my case","created_at":"2021-08-26T19:48:30.151Z","created_by":{"email":null,"full_name":null,"username":"elastic"},"owner":"securitySolution","pushed_at":null,"pushed_by":null,"type":"user","updated_at":null,"updated_by":null},"coreMigrationVersion":"8.0.0","id":"9687c220-06a6-11ec-b3f9-3d05c48a7d46","migrationVersion":{"cases-comments":"7.16.0"},"references":[{"id":"85541260-06a6-11ec-b3f9-3d05c48a7d46","name":"associated-cases","type":"cases"}],"score":null,"sort":[1630007310151,9470],"type":"cases-comments","updated_at":"2021-08-26T19:48:30.161Z","version":"WzM0NDIsMV0="} +{"attributes":{"action":"create","action_at":"2021-08-26T19:48:30.151Z","action_by":{"email":null,"full_name":null,"username":"elastic"},"action_field":["comment"],"new_value":"{\"comment\":\"A comment for my case\",\"type\":\"user\",\"owner\":\"securitySolution\"}","old_value":null,"owner":"securitySolution"},"coreMigrationVersion":"8.0.0","id":"9710c840-06a6-11ec-b3f9-3d05c48a7d46","migrationVersion":{"cases-user-actions":"7.14.0"},"references":[{"id":"85541260-06a6-11ec-b3f9-3d05c48a7d46","name":"associated-cases","type":"cases"},{"id":"9687c220-06a6-11ec-b3f9-3d05c48a7d46","name":"associated-cases-comments","type":"cases-comments"}],"score":null,"sort":[1630007310151,9542],"type":"cases-user-actions","updated_at":"2021-08-26T19:48:31.044Z","version":"WzM1MTIsMV0="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":4,"missingRefCount":0,"missingReferences":[]} diff --git a/x-pack/test/case_api_integration/common/fixtures/saved_object_exports/single_case_with_connector_update_to_none.ndjson b/x-pack/test/case_api_integration/common/fixtures/saved_object_exports/single_case_with_connector_update_to_none.ndjson new file mode 100644 index 0000000000000..4f4476df376cc --- /dev/null +++ b/x-pack/test/case_api_integration/common/fixtures/saved_object_exports/single_case_with_connector_update_to_none.ndjson @@ -0,0 +1,6 @@ +{"attributes":{"actionTypeId":".jira","config":{"apiUrl":"https://cases-testing.atlassian.net","projectKey":"TPN"},"isMissingSecrets":true,"name":"A jira connector"},"coreMigrationVersion":"8.0.0","id":"1cd34740-06ad-11ec-babc-0b08808e8e01","migrationVersion":{"action":"7.14.0"},"references":[],"type":"action","updated_at":"2021-08-26T20:35:12.447Z","version":"WzM1ODQsMV0="} +{"attributes":{"closed_at":null,"closed_by":null,"connector":{"fields":[],"name":"none","type":".none"},"created_at":"2021-08-26T20:35:42.131Z","created_by":{"email":null,"full_name":null,"username":"elastic"},"description":"super description","external_service":{"connector_name":"A jira connector","external_id":"10125","external_title":"TPN-118","external_url":"https://cases-testing.atlassian.net/browse/TPN-118","pushed_at":"2021-08-26T20:35:44.302Z","pushed_by":{"email":null,"full_name":null,"username":"elastic"}},"owner":"securitySolution","settings":{"syncAlerts":true},"status":"open","tags":["other tags"],"title":"A case with a connector","type":"individual","updated_at":"2021-08-26T20:36:35.536Z","updated_by":{"email":null,"full_name":null,"username":"elastic"}},"coreMigrationVersion":"8.0.0","id":"2e85c3f0-06ad-11ec-babc-0b08808e8e01","migrationVersion":{"cases":"7.15.0"},"references":[{"id":"1cd34740-06ad-11ec-babc-0b08808e8e01","name":"pushConnectorId","type":"action"}],"type":"cases","updated_at":"2021-08-26T20:36:35.537Z","version":"WzM1OTIsMV0="} +{"attributes":{"action":"create","action_at":"2021-08-26T20:35:42.131Z","action_by":{"email":null,"full_name":null,"username":"elastic"},"action_field":["description","status","tags","title","connector","settings","owner"],"new_value":"{\"type\":\"individual\",\"title\":\"A case with a connector\",\"tags\":[\"other tags\"],\"description\":\"super description\",\"connector\":{\"id\":\"1cd34740-06ad-11ec-babc-0b08808e8e01\",\"name\":\"A jira connector\",\"type\":\".jira\",\"fields\":{\"issueType\":\"10002\",\"parent\":null,\"priority\":\"High\"}},\"settings\":{\"syncAlerts\":true},\"owner\":\"securitySolution\"}","old_value":null,"owner":"securitySolution"},"coreMigrationVersion":"8.0.0","id":"2e9db8c0-06ad-11ec-babc-0b08808e8e01","migrationVersion":{"cases-user-actions":"7.14.0"},"references":[{"id":"2e85c3f0-06ad-11ec-babc-0b08808e8e01","name":"associated-cases","type":"cases"}],"score":null,"sort":[1630010142131,4024],"type":"cases-user-actions","updated_at":"2021-08-26T20:35:42.284Z","version":"WzM1ODksMV0="} +{"attributes":{"action":"push-to-service","action_at":"2021-08-26T20:35:44.302Z","action_by":{"email":null,"full_name":null,"username":"elastic"},"action_field":["pushed"],"new_value":"{\"pushed_at\":\"2021-08-26T20:35:44.302Z\",\"pushed_by\":{\"username\":\"elastic\",\"full_name\":null,\"email\":null},\"connector_id\":\"1cd34740-06ad-11ec-babc-0b08808e8e01\",\"connector_name\":\"A jira connector\",\"external_id\":\"10125\",\"external_title\":\"TPN-118\",\"external_url\":\"https://cases-testing.atlassian.net/browse/TPN-118\"}","old_value":null,"owner":"securitySolution"},"coreMigrationVersion":"8.0.0","id":"2fd1cbf0-06ad-11ec-babc-0b08808e8e01","migrationVersion":{"cases-user-actions":"7.14.0"},"references":[{"id":"2e85c3f0-06ad-11ec-babc-0b08808e8e01","name":"associated-cases","type":"cases"}],"score":null,"sort":[1630010144302,4029],"type":"cases-user-actions","updated_at":"2021-08-26T20:35:44.303Z","version":"WzM1OTAsMV0="} +{"attributes":{"action":"update","action_at":"2021-08-26T20:36:35.536Z","action_by":{"email":null,"full_name":null,"username":"elastic"},"action_field":["connector"],"new_value":"{\"id\":\"none\",\"name\":\"none\",\"type\":\".none\",\"fields\":null}","old_value":"{\"id\":\"1cd34740-06ad-11ec-babc-0b08808e8e01\",\"name\":\"A jira connector\",\"type\":\".jira\",\"fields\":{\"issueType\":\"10002\",\"parent\":null,\"priority\":\"High\"}}","owner":"securitySolution"},"coreMigrationVersion":"8.0.0","id":"4ee9b250-06ad-11ec-babc-0b08808e8e01","migrationVersion":{"cases-user-actions":"7.14.0"},"references":[{"id":"2e85c3f0-06ad-11ec-babc-0b08808e8e01","name":"associated-cases","type":"cases"}],"score":null,"sort":[1630010195536,4033],"type":"cases-user-actions","updated_at":"2021-08-26T20:36:36.469Z","version":"WzM1OTMsMV0="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":5,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/import_export.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/import_export.ts new file mode 100644 index 0000000000000..df4e858e8a290 --- /dev/null +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/import_export.ts @@ -0,0 +1,209 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { join } from 'path'; +import { ObjectRemover as ActionsRemover } from '../../../../../alerting_api_integration/common/lib'; +import { + deleteAllCaseItems, + createCase, + createComment, + findCases, + getCaseUserActions, +} from '../../../../common/lib/utils'; +import { getPostCaseRequest, postCommentUserReq } from '../../../../common/lib/mock'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import { + AttributesTypeUser, + CommentsResponse, + CASES_URL, + CaseType, +} from '../../../../../../plugins/cases/common'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('import and export cases', () => { + const actionsRemover = new ActionsRemover(supertest); + + afterEach(async () => { + await deleteAllCaseItems(es); + await actionsRemover.removeAll(); + }); + + it('exports a case with its associated user actions and comments', async () => { + const caseRequest = getPostCaseRequest(); + const postedCase = await createCase(supertest, caseRequest); + await createComment({ + supertest, + caseId: postedCase.id, + params: postCommentUserReq, + }); + + const { text } = await supertest + .post(`/api/saved_objects/_export`) + .send({ + type: ['cases'], + excludeExportDetails: true, + includeReferencesDeep: true, + }) + .set('kbn-xsrf', 'true'); + + const objects = ndjsonToObject(text); + + expect(objects).to.have.length(4); + + // should be the case + expect(objects[0].attributes.title).to.eql(caseRequest.title); + expect(objects[0].attributes.description).to.eql(caseRequest.description); + expect(objects[0].attributes.connector.type).to.eql(caseRequest.connector.type); + expect(objects[0].attributes.connector.name).to.eql(caseRequest.connector.name); + expect(objects[0].attributes.connector.fields).to.eql([]); + expect(objects[0].attributes.settings).to.eql(caseRequest.settings); + + // should be two user actions + expect(objects[1].attributes.action).to.eql('create'); + + const parsedCaseNewValue = JSON.parse(objects[1].attributes.new_value); + const { + connector: { id: ignoreParsedId, ...restParsedConnector }, + ...restParsedCreateCase + } = parsedCaseNewValue; + + const { + connector: { id: ignoreConnectorId, ...restConnector }, + ...restCreateCase + } = caseRequest; + + expect(restParsedCreateCase).to.eql({ ...restCreateCase, type: CaseType.individual }); + expect(restParsedConnector).to.eql(restConnector); + + expect(objects[1].attributes.old_value).to.eql(null); + expect(includesAllRequiredFields(objects[1].attributes.action_field)).to.eql(true); + + // should be the comment + expect(objects[2].attributes.comment).to.eql(postCommentUserReq.comment); + expect(objects[2].attributes.type).to.eql(postCommentUserReq.type); + + expect(objects[3].attributes.action).to.eql('create'); + expect(JSON.parse(objects[3].attributes.new_value)).to.eql(postCommentUserReq); + expect(objects[3].attributes.old_value).to.eql(null); + expect(objects[3].attributes.action_field).to.eql(['comment']); + }); + + it('imports a case with a comment and user actions', async () => { + await supertest + .post('/api/saved_objects/_import') + .query({ overwrite: true }) + .attach( + 'file', + join( + __dirname, + '../../../../common/fixtures/saved_object_exports/single_case_user_actions_one_comment.ndjson' + ) + ) + .set('kbn-xsrf', 'true') + .expect(200); + + const findResponse = await findCases({ supertest, query: {} }); + expect(findResponse.total).to.eql(1); + expect(findResponse.cases[0].title).to.eql('A case to export'); + expect(findResponse.cases[0].description).to.eql('a description'); + + const { body: commentsResponse }: { body: CommentsResponse } = await supertest + .get(`${CASES_URL}/${findResponse.cases[0].id}/comments/_find`) + .send() + .expect(200); + + const comment = (commentsResponse.comments[0] as unknown) as AttributesTypeUser; + expect(comment.comment).to.eql('A comment for my case'); + + const userActions = await getCaseUserActions({ + supertest, + caseID: findResponse.cases[0].id, + }); + + expect(userActions).to.have.length(2); + expect(userActions[0].action).to.eql('create'); + expect(includesAllRequiredFields(userActions[0].action_field)).to.eql(true); + + expect(userActions[1].action).to.eql('create'); + expect(userActions[1].action_field).to.eql(['comment']); + expect(userActions[1].old_value).to.eql(null); + expect(JSON.parse(userActions[1].new_value!)).to.eql({ + comment: 'A comment for my case', + type: 'user', + owner: 'securitySolution', + }); + }); + + it('imports a case with a connector', async () => { + await supertest + .post('/api/saved_objects/_import') + .query({ overwrite: true }) + .attach( + 'file', + join( + __dirname, + '../../../../common/fixtures/saved_object_exports/single_case_with_connector_update_to_none.ndjson' + ) + ) + .set('kbn-xsrf', 'true') + .expect(200); + + actionsRemover.add('default', '1cd34740-06ad-11ec-babc-0b08808e8e01', 'action', 'actions'); + + const findResponse = await findCases({ supertest, query: {} }); + expect(findResponse.total).to.eql(1); + expect(findResponse.cases[0].title).to.eql('A case with a connector'); + expect(findResponse.cases[0].description).to.eql('super description'); + + const userActions = await getCaseUserActions({ + supertest, + caseID: findResponse.cases[0].id, + }); + + expect(userActions).to.have.length(3); + expect(userActions[0].action).to.eql('create'); + expect(includesAllRequiredFields(userActions[0].action_field)).to.eql(true); + + expect(userActions[1].action).to.eql('push-to-service'); + expect(userActions[1].action_field).to.eql(['pushed']); + expect(userActions[1].old_value).to.eql(null); + + const parsedPushNewValue = JSON.parse(userActions[1].new_value!); + expect(parsedPushNewValue.connector_name).to.eql('A jira connector'); + expect(parsedPushNewValue.connector_id).to.eql('1cd34740-06ad-11ec-babc-0b08808e8e01'); + + expect(userActions[2].action).to.eql('update'); + expect(userActions[2].action_field).to.eql(['connector']); + + const parsedUpdateNewValue = JSON.parse(userActions[2].new_value!); + expect(parsedUpdateNewValue.id).to.eql('none'); + }); + }); +}; + +const ndjsonToObject = (input: string) => { + return input.split('\n').map((str) => JSON.parse(str)); +}; + +const includesAllRequiredFields = (actionFields: string[]): boolean => { + const requiredFields = [ + 'description', + 'status', + 'tags', + 'title', + 'connector', + 'settings', + 'owner', + ]; + + return requiredFields.every((field) => actionFields.includes(field)); +}; diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts index 9b24de26245f4..fba60634cc3d7 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts @@ -20,6 +20,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./alerts/get_cases')); loadTestFile(require.resolve('./alerts/get_alerts_attached_to_case')); loadTestFile(require.resolve('./cases/delete_cases')); + loadTestFile(require.resolve('./cases/import_export')); loadTestFile(require.resolve('./cases/find_cases')); loadTestFile(require.resolve('./cases/get_case')); loadTestFile(require.resolve('./cases/patch_cases'));