diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 0c89dc73bcd38..5d4725f0b2e24 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -40331,9 +40331,9 @@ components: - assistant type: string Security_AI_Assistant_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_AI_Assistant_API_NormalizedAnonymizationFieldError: type: object @@ -43097,9 +43097,9 @@ components: - severity - $ref: '#/components/schemas/Security_Detections_API_NewTermsRuleCreateFields' Security_Detections_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Detections_API_NormalizedRuleAction: additionalProperties: false @@ -46301,9 +46301,9 @@ components: - text type: string Security_Endpoint_Exceptions_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Endpoint_Exceptions_API_PlatformErrorResponse: type: object @@ -46604,9 +46604,9 @@ components: required: - hostStatuses Security_Endpoint_Management_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Endpoint_Management_API_NoParametersRequestSchema: type: object @@ -47788,9 +47788,9 @@ components: - text type: string Security_Exceptions_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Exceptions_API_PlatformErrorResponse: type: object @@ -48034,9 +48034,9 @@ components: - text type: string Security_Lists_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Lists_API_PlatformErrorResponse: type: object diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index d9dbce0c460ec..b8f8fa29e84ee 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -47829,9 +47829,9 @@ components: - assistant type: string Security_AI_Assistant_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_AI_Assistant_API_NormalizedAnonymizationFieldError: type: object @@ -50775,9 +50775,9 @@ components: - severity - $ref: '#/components/schemas/Security_Detections_API_NewTermsRuleCreateFields' Security_Detections_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Detections_API_NormalizedRuleAction: additionalProperties: false @@ -53986,9 +53986,9 @@ components: - text type: string Security_Endpoint_Exceptions_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Endpoint_Exceptions_API_PlatformErrorResponse: type: object @@ -54289,9 +54289,9 @@ components: required: - hostStatuses Security_Endpoint_Management_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Endpoint_Management_API_NoParametersRequestSchema: type: object @@ -55473,9 +55473,9 @@ components: - text type: string Security_Exceptions_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Exceptions_API_PlatformErrorResponse: type: object @@ -55719,9 +55719,9 @@ components: - text type: string Security_Lists_API_NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string Security_Lists_API_PlatformErrorResponse: type: object diff --git a/packages/kbn-openapi-common/jest.config.js b/packages/kbn-openapi-common/jest.config.js new file mode 100644 index 0000000000000..c8e533f9d7ed8 --- /dev/null +++ b/packages/kbn-openapi-common/jest.config.js @@ -0,0 +1,14 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-openapi-common'], +}; diff --git a/packages/kbn-openapi-common/schemas/primitives.gen.ts b/packages/kbn-openapi-common/schemas/primitives.gen.ts index 4f8b19495022d..03977a29b9973 100644 --- a/packages/kbn-openapi-common/schemas/primitives.gen.ts +++ b/packages/kbn-openapi-common/schemas/primitives.gen.ts @@ -17,15 +17,13 @@ */ import { z } from '@kbn/zod'; +import { isNonEmptyString } from '@kbn/zod-helpers'; /** - * A string that is not empty and does not contain only whitespace + * A string that does not contain only whitespace characters */ export type NonEmptyString = z.infer; -export const NonEmptyString = z - .string() - .min(1) - .regex(/^(?! *$).+$/); +export const NonEmptyString = z.string().min(1).superRefine(isNonEmptyString); /** * A universally unique identifier diff --git a/packages/kbn-openapi-common/schemas/primitives.schema.yaml b/packages/kbn-openapi-common/schemas/primitives.schema.yaml index 177ad2ed30ecc..84e4367192725 100644 --- a/packages/kbn-openapi-common/schemas/primitives.schema.yaml +++ b/packages/kbn-openapi-common/schemas/primitives.schema.yaml @@ -8,9 +8,9 @@ components: schemas: NonEmptyString: type: string - pattern: ^(?! *$).+$ minLength: 1 - description: A string that is not empty and does not contain only whitespace + format: nonempty + description: A string that does not contain only whitespace characters UUID: type: string diff --git a/packages/kbn-openapi-common/schemas/primitives.test.ts b/packages/kbn-openapi-common/schemas/primitives.test.ts new file mode 100644 index 0000000000000..b83f5e6d34637 --- /dev/null +++ b/packages/kbn-openapi-common/schemas/primitives.test.ts @@ -0,0 +1,44 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +import { NonEmptyString } from './primitives.gen'; + +describe('NonEmptyString', () => { + describe('accepts ', () => { + // \t\r\n\f + test('accepts newline chars', () => { + expect(() => NonEmptyString.parse('hello \nworld')).not.toThrow(); + }); + test('accepts tab chars', () => { + expect(() => NonEmptyString.parse('hello \tworld')).not.toThrow(); + }); + test('accepts carriage return chars', () => { + expect(() => NonEmptyString.parse('hello \rworld')).not.toThrow(); + }); + test('accepts form feed return chars', () => { + expect(() => NonEmptyString.parse('hello \fworld')).not.toThrow(); + }); + }); + describe('rejects', () => { + test('rejects only tab chars chars', () => { + expect(() => NonEmptyString.parse('\t\t\t\t')).toThrow(); + }); + test('rejects only newline chars chars', () => { + expect(() => NonEmptyString.parse('\n\n\n\n\n')).toThrow(); + }); + test('rejects only carriage return chars chars', () => { + expect(() => NonEmptyString.parse('\r\r\r\r')).toThrow(); + }); + test('rejects only form feed chars chars', () => { + expect(() => NonEmptyString.parse('\f\f\f\f\f')).toThrow(); + }); + test('rejects comment with just spaces', () => { + expect(() => NonEmptyString.parse(' ')).toThrow(); + }); + }); +}); diff --git a/packages/kbn-openapi-common/tsconfig.json b/packages/kbn-openapi-common/tsconfig.json index ca7d7e4715362..29a271ba4840d 100644 --- a/packages/kbn-openapi-common/tsconfig.json +++ b/packages/kbn-openapi-common/tsconfig.json @@ -8,5 +8,6 @@ "include": ["**/*.ts"], "kbn_references": [ "@kbn/zod", + "@kbn/zod-helpers", ] } diff --git a/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars index 759b0d9294b8a..b3b1b72bf4154 100644 --- a/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars +++ b/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars @@ -9,7 +9,7 @@ import type { ZodTypeDef } from '@kbn/zod'; import { z } from '@kbn/zod'; -import { requiredOptional, isValidDateMath, ArrayFromString, BooleanFromString } from '@kbn/zod-helpers'; +import { requiredOptional, isValidDateMath, isNonEmptyString, ArrayFromString, BooleanFromString } from '@kbn/zod-helpers'; {{#each imports}} import { diff --git a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars index 8e4c5aef616fb..de9b66cee31d6 100644 --- a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars +++ b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars @@ -124,5 +124,8 @@ z.unknown() {{~#if (eq format 'date-math')}}.superRefine(isValidDateMath){{/if~}} {{~#if (eq format 'uuid')}}.uuid(){{/if~}} {{~#if pattern}}.regex(/{{pattern}}/){{/if~}} + {{~#if (eq format 'trim')}}.trim(){{/if~}} + {{~#if (eq format 'nonempty')}}.superRefine(isNonEmptyString){{/if~}} + {{~/if~}} {{~/inline~}} diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml index 366efe23d586b..2aac93167d2a9 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml +++ b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml @@ -846,9 +846,9 @@ components: - text type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string PlatformErrorResponse: type: object diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml index 0ecce40ef34d3..1257b37622add 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml +++ b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml @@ -846,9 +846,9 @@ components: - text type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string PlatformErrorResponse: type: object diff --git a/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml index bf290e872f915..d02bd360cc313 100644 --- a/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml +++ b/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml @@ -1846,9 +1846,9 @@ components: - text type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string PlatformErrorResponse: type: object diff --git a/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml index 115658261c909..885028d7e2d94 100644 --- a/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml +++ b/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml @@ -1846,9 +1846,9 @@ components: - text type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string PlatformErrorResponse: type: object diff --git a/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml index 17eef19505e40..ef88149b49b32 100644 --- a/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml +++ b/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml @@ -1528,9 +1528,9 @@ components: - text type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string PlatformErrorResponse: type: object diff --git a/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml index 5348d9404a0e3..e3558193b30da 100644 --- a/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml +++ b/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml @@ -1528,9 +1528,9 @@ components: - text type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string PlatformErrorResponse: type: object diff --git a/packages/kbn-zod-helpers/index.ts b/packages/kbn-zod-helpers/index.ts index cbd864e327a20..65624b7ec6c80 100644 --- a/packages/kbn-zod-helpers/index.ts +++ b/packages/kbn-zod-helpers/index.ts @@ -16,3 +16,4 @@ export * from './src/required_optional'; export * from './src/safe_parse_result'; export * from './src/stringify_zod_error'; export * from './src/build_route_validation_with_zod'; +export * from './src/non_empty_string'; diff --git a/packages/kbn-zod-helpers/src/non_empty_string.ts b/packages/kbn-zod-helpers/src/non_empty_string.ts new file mode 100644 index 0000000000000..d007c2f4f0a25 --- /dev/null +++ b/packages/kbn-zod-helpers/src/non_empty_string.ts @@ -0,0 +1,19 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import * as z from '@kbn/zod'; + +export function isNonEmptyString(input: string, ctx: z.RefinementCtx): void { + if (input.trim() === '') { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'No empty strings allowed', + }); + } +} diff --git a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml index 8f80e61c07040..726f5faba2edb 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml @@ -978,9 +978,9 @@ components: - assistant type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string NormalizedAnonymizationFieldError: type: object diff --git a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml index 97c18a2f77b6e..81112f1470547 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml @@ -978,9 +978,9 @@ components: - assistant type: string NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string NormalizedAnonymizationFieldError: type: object diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts index 1697011a08532..a49d6bc6e41b7 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts @@ -15,15 +15,13 @@ */ import { z } from '@kbn/zod'; +import { isNonEmptyString } from '@kbn/zod-helpers'; /** - * A string that is not empty and does not contain only whitespace + * A string that does not contain only whitespace characters */ export type NonEmptyString = z.infer; -export const NonEmptyString = z - .string() - .min(1) - .regex(/^(?! *$).+$/); +export const NonEmptyString = z.string().min(1).superRefine(isNonEmptyString); /** * A universally unique identifier diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml index 348868746fb6c..b400548631ed1 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml @@ -8,9 +8,9 @@ components: schemas: NonEmptyString: type: string - pattern: ^(?! *$).+$ + format: nonempty minLength: 1 - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters UUID: type: string @@ -33,4 +33,3 @@ components: enum: - 'asc' - 'desc' - diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap index c283cc1087682..0f5a4143a5c99 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap @@ -5737,7 +5737,6 @@ Object { "field_names": Object { "items": Object { "minLength": 1, - "pattern": "^(?! *$).+$", "type": "string", }, "minItems": 1, @@ -6405,7 +6404,6 @@ Object { "field_names": Object { "items": Object { "minLength": 1, - "pattern": "^(?! *$).+$", "type": "string", }, "minItems": 1, @@ -7136,7 +7134,6 @@ Object { "field_names": Object { "items": Object { "minLength": 1, - "pattern": "^(?! *$).+$", "type": "string", }, "minItems": 1, @@ -7785,7 +7782,6 @@ Object { "field_names": Object { "items": Object { "minLength": 1, - "pattern": "^(?! *$).+$", "type": "string", }, "minItems": 1, @@ -8489,7 +8485,6 @@ Object { "field_names": Object { "items": Object { "minLength": 1, - "pattern": "^(?! *$).+$", "type": "string", }, "minItems": 1, @@ -9195,7 +9190,6 @@ Object { "field_names": Object { "items": Object { "minLength": 1, - "pattern": "^(?! *$).+$", "type": "string", }, "minItems": 1, @@ -9901,7 +9895,6 @@ Object { "field_names": Object { "items": Object { "minLength": 1, - "pattern": "^(?! *$).+$", "type": "string", }, "minItems": 1, diff --git a/x-pack/plugins/security_solution/common/api/model/primitives.gen.ts b/x-pack/plugins/security_solution/common/api/model/primitives.gen.ts index ed3174434cb36..393cfe7a21c53 100644 --- a/x-pack/plugins/security_solution/common/api/model/primitives.gen.ts +++ b/x-pack/plugins/security_solution/common/api/model/primitives.gen.ts @@ -15,15 +15,13 @@ */ import { z } from '@kbn/zod'; +import { isNonEmptyString } from '@kbn/zod-helpers'; /** - * A string that is not empty and does not contain only whitespace + * A string that does not contain only whitespace characters */ export type NonEmptyString = z.infer; -export const NonEmptyString = z - .string() - .min(1) - .regex(/^(?! *$).+$/); +export const NonEmptyString = z.string().min(1).superRefine(isNonEmptyString); /** * A universally unique identifier diff --git a/x-pack/plugins/security_solution/common/api/model/primitives.schema.yaml b/x-pack/plugins/security_solution/common/api/model/primitives.schema.yaml index 177ad2ed30ecc..2d4e184928fca 100644 --- a/x-pack/plugins/security_solution/common/api/model/primitives.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/model/primitives.schema.yaml @@ -8,9 +8,9 @@ components: schemas: NonEmptyString: type: string - pattern: ^(?! *$).+$ + format: nonempty minLength: 1 - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters UUID: type: string diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/common.gen.ts b/x-pack/plugins/security_solution/common/siem_migrations/model/common.gen.ts index c6d0959cc10cf..f55b87f7af703 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/common.gen.ts +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/common.gen.ts @@ -15,6 +15,13 @@ */ import { z } from '@kbn/zod'; +import { isNonEmptyString } from '@kbn/zod-helpers'; + +/** + * A string that does not contain only whitespace characters + */ +export type NonEmptyString = z.infer; +export const NonEmptyString = z.string().min(1).superRefine(isNonEmptyString); /** * The GenAI connector id to use. diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/common.schema.yaml b/x-pack/plugins/security_solution/common/siem_migrations/model/common.schema.yaml index 14a5160427f8a..9e15bd857c728 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/common.schema.yaml +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/common.schema.yaml @@ -6,6 +6,11 @@ paths: {} components: x-codegen-enabled: true schemas: + NonEmptyString: + type: string + format: nonempty + minLength: 1 + description: A string that does not contain only whitespace characters ConnectorId: type: string description: The GenAI connector id to use. diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 55514516f43da..dfc824035575d 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -4186,9 +4186,9 @@ components: - severity - $ref: '#/components/schemas/NewTermsRuleCreateFields' NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string NormalizedRuleAction: additionalProperties: false diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml index 585dec4f3074d..62d604ec727db 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml @@ -706,9 +706,9 @@ components: required: - hostStatuses NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string NoParametersRequestSchema: type: object diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 58456e71140a0..f81cc1227c893 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -3335,9 +3335,9 @@ components: - severity - $ref: '#/components/schemas/NewTermsRuleCreateFields' NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string NormalizedRuleAction: additionalProperties: false diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml index ded6f6558b017..ee89d61a58b52 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml @@ -706,9 +706,9 @@ components: required: - hostStatuses NonEmptyString: - description: A string that is not empty and does not contain only whitespace + description: A string that does not contain only whitespace characters + format: nonempty minLength: 1 - pattern: ^(?! *$).+$ type: string NoParametersRequestSchema: type: object diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts index dfc0603598a00..4b4653d194745 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts @@ -92,7 +92,7 @@ describe('setAlertAssigneesRoute', () => { const result = server.validate(request); expect(result.badRequest).toHaveBeenCalledWith( - 'ids.0: String must contain at least 1 character(s), ids.0: Invalid' + 'ids.0: String must contain at least 1 character(s), ids.0: No empty strings allowed' ); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/trial_license_complete_tier/assignments/assignments.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/trial_license_complete_tier/assignments/assignments.ts index b445c6f81f99c..436ebc469c25e 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/trial_license_complete_tier/assignments/assignments.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/trial_license_complete_tier/assignments/assignments.ts @@ -65,7 +65,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', message: - '[request body]: ids.1: String must contain at least 1 character(s), ids.1: Invalid', + '[request body]: ids.1: String must contain at least 1 character(s), ids.1: No empty strings allowed', statusCode: 400, }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/create_exception_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/create_exception_list_items.ts index b9a602c9fbaa3..4eed89e8d83c4 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/create_exception_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/create_exception_list_items.ts @@ -68,6 +68,86 @@ export default ({ getService }: FtrProviderContext) => { ); }); + it('should create a simple exception list item with a list item id and a comment containing newline chars', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ + ...getCreateExceptionListItemMinimalSchemaMock(), + comments: [{ comment: 'hello\nworld' }], + }) + .expect(200); + + const { comments } = removeExceptionListItemServerGeneratedProperties(body); + + expect(comments?.[0]?.comment).to.eql('hello\nworld'); + }); + + it('should not create an item when the comment is empty', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ + ...getCreateExceptionListItemMinimalSchemaMock(), + comments: [{ comment: '' }], + }) + .expect(400); + expect(body.message).to.contain('No empty strings allowed'); + }); + + it('should not create an item when the comment is only newline chars', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ + ...getCreateExceptionListItemMinimalSchemaMock(), + comments: [{ comment: '\n\n\n\n' }], + }) + .expect(400); + expect(body.message).to.contain('No empty strings allowed'); + }); + + it('should create an item when the comments array is empty', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ + ...getCreateExceptionListItemMinimalSchemaMock(), + comments: [], + }) + .expect(200); + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + + expect(bodyToCompare).to.eql( + getExceptionListItemResponseMockWithoutAutoGeneratedValues(await utils.getUsername()) + ); + }); + it('should create a match any exception item with multiple case sensitive values', async () => { const entries = [ { diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/find_exception_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/find_exception_list_items.ts index 3753c63ff7693..a13f339cac37c 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/find_exception_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/exception_lists_items/trial_license_complete_tier/items/find_exception_list_items.ts @@ -135,6 +135,53 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + it('should return matching items when search is passed in and comments have newline chars', async () => { + // create exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListDetectionSchemaMock()) + .expect(200); + + // create exception list items + await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ + ...getCreateExceptionListItemMinimalSchemaMockWithoutId(), + list_id: getCreateExceptionListDetectionSchemaMock().list_id, + item_id: '1', + entries: [ + { field: 'host.name', value: 'some host', operator: 'included', type: 'match' }, + ], + comments: [{ comment: 'hello\nworld' }], + }) + .expect(200); + await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ + ...getCreateExceptionListItemMinimalSchemaMockWithoutId(), + item_id: '2', + list_id: getCreateExceptionListDetectionSchemaMock().list_id, + entries: [{ field: 'foo', operator: 'included', type: 'exists' }], + }) + .expect(200); + + const { body } = await supertest + .get( + `${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${ + getCreateExceptionListMinimalSchemaMock().list_id + }&namespace_type=single&page=1&per_page=25&search=host&sort_field=exception-list.created_at&sort_order=desc` + ) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + body.data = [removeExceptionListItemServerGeneratedProperties(body.data[0])]; + expect(body.data[0].comments[0].comment).to.eql('hello\nworld'); + }); + it('should return 404 if given a list_id that does not exist', async () => { const { body } = await supertest .get(`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=non_exist`)