diff --git a/x-pack/platform/plugins/shared/cases/common/constants/index.ts b/x-pack/platform/plugins/shared/cases/common/constants/index.ts index d586ba21a63cc..0122f91fce9cc 100644 --- a/x-pack/platform/plugins/shared/cases/common/constants/index.ts +++ b/x-pack/platform/plugins/shared/cases/common/constants/index.ts @@ -129,6 +129,8 @@ export const MAX_SUPPORTED_CONNECTORS_RETURNED = 1000 as const; */ export const MAX_TITLE_LENGTH = 160 as const; +export const MAX_RULE_NAME_LENGTH = 100 as const; +export const MAX_SUFFIX_LENGTH = 60 as const; export const MAX_CATEGORY_LENGTH = 50 as const; export const MAX_DESCRIPTION_LENGTH = 30000 as const; export const MAX_COMMENT_LENGTH = 30000 as const; diff --git a/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.test.ts b/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.test.ts index bc21c0f4e8a95..7cdcc059fdb38 100644 --- a/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.test.ts +++ b/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.test.ts @@ -14,6 +14,7 @@ import { MAX_LENGTH_PER_TAG, MAX_TAGS_PER_CASE, MAX_TITLE_LENGTH, + MAX_SUFFIX_LENGTH, } from '../../../common/constants'; import { CasesOracleService } from './cases_oracle_service'; import { CasesService } from './cases_service'; @@ -693,13 +694,72 @@ describe('CasesConnectorExecutor', () => { }); const title = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].title; - expect(title.length).toBeLessThanOrEqual(MAX_TITLE_LENGTH); expect(title).toMatchInlineSnapshot( - `"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... (2) (Auto-created)"` + `"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... (2) (Auto-created)"` ); }); + it(`trims the grouping description correctly if the cases title is bigger than ${MAX_TITLE_LENGTH}`, async () => { + mockBulkGetRecords.mockResolvedValue([{ ...oracleRecords[0], counter: 2 }]); + casesClientMock.cases.bulkCreate.mockResolvedValue({ cases: [cases[0]] }); + casesClientMock.cases.bulkGet.mockResolvedValue({ + cases: [], + errors: [ + { + error: 'Not found', + message: 'Not found', + status: 404, + caseId: 'mock-id-1', + }, + ], + }); + + const ruleName = 'a'.repeat(120); + + await connectorExecutor.execute({ + ...params, + rule: { ...params.rule, name: ruleName }, + groupingBy: ['rule.name'], + }); + + const title = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].title; + + const index = title.indexOf(' - Grouping by'); + const suffix = title.slice(index); + + expect(title.length).toBeLessThanOrEqual(MAX_TITLE_LENGTH); + expect(suffix.length).toBeLessThanOrEqual(MAX_SUFFIX_LENGTH); + }); + + it(`does not trim the title if it is shorter than ${MAX_TITLE_LENGTH}`, async () => { + mockBulkGetRecords.mockResolvedValue([{ ...oracleRecords[0], counter: 2 }]); + casesClientMock.cases.bulkCreate.mockResolvedValue({ cases: [cases[0]] }); + casesClientMock.cases.bulkGet.mockResolvedValue({ + cases: [], + errors: [ + { + error: 'Not found', + message: 'Not found', + status: 404, + caseId: 'mock-id-1', + }, + ], + }); + + const ruleName = 'a'.repeat(15); + await connectorExecutor.execute({ + ...params, + rule: { ...params.rule, name: ruleName }, + groupingBy: ['rule.name'], + }); + + const title = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].title; + + expect(title.length).toBeLessThanOrEqual(MAX_TITLE_LENGTH); + expect(title).not.toContain('...'); + }); + it(`trims tags that are bigger than ${MAX_LENGTH_PER_TAG} characters`, async () => { mockBulkGetRecords.mockResolvedValue([oracleRecords[0]]); casesClientMock.cases.bulkCreate.mockResolvedValue({ cases: [cases[0]] }); diff --git a/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.ts b/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.ts index 19f480ce48e1e..ecf9e2d618ca2 100644 --- a/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.ts +++ b/x-pack/platform/plugins/shared/cases/server/connectors/cases/cases_connector_executor.ts @@ -22,6 +22,8 @@ import { MAX_LENGTH_PER_TAG, MAX_TAGS_PER_CASE, MAX_TITLE_LENGTH, + MAX_RULE_NAME_LENGTH, + MAX_SUFFIX_LENGTH, } from '../../../common/constants'; import type { BulkCreateCasesRequest } from '../../../common/types/api'; import type { Case } from '../../../common'; @@ -819,22 +821,42 @@ export class CasesConnectorExecutor { }) .join(' & '); - const suffix = `${ - groupingDescription.length > 0 ? ` - ${GROUPED_BY_TITLE(groupingDescription)}` : '' - }${ - oracleCounter > INITIAL_ORACLE_RECORD_COUNTER ? ` (${oracleCounter})` : '' - } (${AUTO_CREATED_TITLE})`; + const oracleCounterString = + oracleCounter > INITIAL_ORACLE_RECORD_COUNTER ? ` (${oracleCounter})` : ''; - const ruleNameTrimmed = params.rule.name.slice( - 0, - MAX_TITLE_LENGTH - suffix.length - totalDots - 1 - ); + const staticSuffixStart = groupingDescription.length > 0 ? ` - ${GROUPED_BY_TITLE('')}` : ''; + + const staticSuffixEnd = `${oracleCounterString} (${AUTO_CREATED_TITLE})`; + + const ruleName = params.rule.name; + + const ruleNameTrimmed = + ruleName.length > MAX_RULE_NAME_LENGTH + ? ruleName.slice(0, MAX_RULE_NAME_LENGTH - totalDots) + : ruleName; const ruleNameTrimmedWithDots = - params.rule.name.length > ruleNameTrimmed.length + ruleName.length > ruleNameTrimmed.length ? `${ruleNameTrimmed}${'.'.repeat(totalDots)}` : ruleNameTrimmed; + const maxSuffixLength = + ruleNameTrimmedWithDots.length < MAX_RULE_NAME_LENGTH + ? MAX_TITLE_LENGTH - ruleNameTrimmedWithDots.length + : MAX_SUFFIX_LENGTH; + + const maxGroupingDescriptionLength = + maxSuffixLength - (staticSuffixStart.length + staticSuffixEnd.length); + + const groupingDescriptionTrimmed = + groupingDescription.length > maxGroupingDescriptionLength + ? `${groupingDescription.slice(0, maxGroupingDescriptionLength - totalDots)}${'.'.repeat( + totalDots + )}` + : groupingDescription; + + const suffix = `${staticSuffixStart}${groupingDescriptionTrimmed}${staticSuffixEnd}`; + return `${ruleNameTrimmedWithDots}${suffix}`; }