From be9b46d911f8648203a4c1d5fe4ccea848020ef7 Mon Sep 17 00:00:00 2001 From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> Date: Tue, 14 May 2024 10:45:54 +0200 Subject: [PATCH] [Fleet] add validation to dataset field in input packages to disallow special characters (#182925) ## Summary Closes https://github.com/elastic/kibana/issues/181044 Added validation to allow only valid index names as dataset name in input packages. Allowing lowercase letters, numbers, dot and underscore (except in the beginning). To verify: - add Custom Logs integration - modfiy dataset to add invalid characters e.g. * - verify that the field shows a validation error - verify that the save button is disabled - verify that valid dataset names can be used image ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- x-pack/plugins/fleet/common/index.ts | 1 + x-pack/plugins/fleet/common/services/index.ts | 6 +- .../common/services/is_valid_namespace.ts | 52 +++++- .../services/validate_package_policy.test.ts | 140 ++++++++++++++ .../services/validate_package_policy.ts | 24 ++- .../steps/components/dataset_combo.tsx | 133 ------------- .../components/dataset_component.test.tsx | 71 +++++++ .../steps/components/dataset_component.tsx | 174 ++++++++++++++++++ .../package_policy_input_var_field.tsx | 38 ++-- .../translations/translations/fr-FR.json | 4 - .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - .../package_policy/input_package_rollback.ts | 7 +- 13 files changed, 477 insertions(+), 181 deletions(-) delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_combo.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.test.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.tsx diff --git a/x-pack/plugins/fleet/common/index.ts b/x-pack/plugins/fleet/common/index.ts index 0c729823f3391..fed73a5653313 100644 --- a/x-pack/plugins/fleet/common/index.ts +++ b/x-pack/plugins/fleet/common/index.ts @@ -73,6 +73,7 @@ export { fleetSetupRouteService, // Package policy helpers isValidNamespace, + isValidDataset, INVALID_NAMESPACE_CHARACTERS, getFileMetadataIndexName, getFileDataIndexName, diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index 3d1fc77f2a373..db7cb41d5fea0 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -16,7 +16,11 @@ export { } from './package_to_package_policy'; export { fullAgentPolicyToYaml } from './full_agent_policy_to_yaml'; export { isPackageLimited, doesAgentPolicyAlreadyIncludePackage } from './limited_package'; -export { isValidNamespace, INVALID_NAMESPACE_CHARACTERS } from './is_valid_namespace'; +export { + isValidDataset, + isValidNamespace, + INVALID_NAMESPACE_CHARACTERS, +} from './is_valid_namespace'; export { isDiffPathProtocol } from './is_diff_path_protocol'; export { LicenseService } from './license'; export * from './is_agent_upgradeable'; diff --git a/x-pack/plugins/fleet/common/services/is_valid_namespace.ts b/x-pack/plugins/fleet/common/services/is_valid_namespace.ts index 49332c4a88156..dcc1a2b9b5cbf 100644 --- a/x-pack/plugins/fleet/common/services/is_valid_namespace.ts +++ b/x-pack/plugins/fleet/common/services/is_valid_namespace.ts @@ -14,37 +14,71 @@ export function isValidNamespace( namespace: string, allowBlankNamespace?: boolean ): { valid: boolean; error?: string } { - if (!namespace.trim() && !allowBlankNamespace) { + return isValidEntity(namespace, 'Namespace', allowBlankNamespace); +} + +export function isValidDataset( + dataset: string, + allowBlank?: boolean +): { valid: boolean; error?: string } { + const { valid, error } = isValidEntity(dataset, 'Dataset', allowBlank); + if (!valid) { + return { valid, error }; + } + if (dataset.startsWith('_') || dataset.startsWith('.')) { + return { + valid: false, + error: i18n.translate( + 'xpack.fleet.datasetValidation.datasetStartsWithUnderscoreErrorMessage', + { + defaultMessage: 'Dataset cannot start with an underscore or dot', + } + ), + }; + } + return { valid, error }; +} + +function isValidEntity( + name: string, + type: string, + allowBlank?: boolean +): { valid: boolean; error?: string } { + if (!name.trim() && !allowBlank) { return { valid: false, error: i18n.translate('xpack.fleet.namespaceValidation.requiredErrorMessage', { - defaultMessage: 'Namespace is required', + defaultMessage: '{type} is required', + values: { type }, }), }; - } else if (namespace !== namespace.toLowerCase()) { + } else if (name !== name.toLowerCase()) { return { valid: false, error: i18n.translate('xpack.fleet.namespaceValidation.lowercaseErrorMessage', { - defaultMessage: 'Namespace must be lowercase', + defaultMessage: '{type} must be lowercase', + values: { type }, }), }; - } else if (INVALID_NAMESPACE_CHARACTERS.test(namespace)) { + } else if (INVALID_NAMESPACE_CHARACTERS.test(name)) { return { valid: false, error: i18n.translate('xpack.fleet.namespaceValidation.invalidCharactersErrorMessage', { - defaultMessage: 'Namespace contains invalid characters', + defaultMessage: '{type} contains invalid characters', + values: { type }, }), }; } // Node.js doesn't have Blob, and browser doesn't have Buffer :) else if ( - (typeof Blob === 'function' && new Blob([namespace]).size > 100) || - (typeof Buffer === 'function' && Buffer.from(namespace).length > 100) + (typeof Blob === 'function' && new Blob([name]).size > 100) || + (typeof Buffer === 'function' && Buffer.from(name).length > 100) ) { return { valid: false, error: i18n.translate('xpack.fleet.namespaceValidation.tooLongErrorMessage', { - defaultMessage: 'Namespace cannot be more than 100 bytes', + defaultMessage: '{type} cannot be more than 100 bytes', + values: { type }, }), }; } diff --git a/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts b/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts index 7f5c6999bce9c..3f443838d485e 100644 --- a/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts @@ -1079,4 +1079,144 @@ describe('Fleet - validatePackagePolicyConfig', () => { expect(res).toEqual(['Secret reference is invalid, id must be a string']); }); }); + + describe('Dataset', () => { + const datasetError = 'Dataset contains invalid characters'; + + const validateDataset = (dataset: string) => { + return validatePackagePolicyConfig( + { + type: 'text', + value: { dataset, package: 'log' }, + }, + { + name: 'data_stream.dataset', + type: 'text', + }, + 'data_stream.dataset', + safeLoad, + 'input' + ); + }; + + it('should return an error message if the value has *', () => { + const res = validateDataset('test*'); + + expect(res).toEqual([datasetError]); + }); + + it('should return an error message if the value has uppercase letter', () => { + const res = validateDataset('Test'); + + expect(res).toEqual(['Dataset must be lowercase']); + }); + + it('should return an error message if the value has _ in the beginning', () => { + const res = validateDataset('_test'); + + expect(res).toEqual(['Dataset cannot start with an underscore or dot']); + }); + + it('should return an error message if the value has . in the beginning', () => { + const res = validateDataset('.test'); + + expect(res).toEqual(['Dataset cannot start with an underscore or dot']); + }); + + it('should not return an error message if the value is valid', () => { + const res = validateDataset('fleet_server.test_dataset'); + + expect(res).toEqual(null); + }); + + it('should not return an error message if the value is undefined', () => { + const res = validatePackagePolicyConfig( + { + type: 'text', + value: undefined, + }, + { + name: 'data_stream.dataset', + type: 'text', + }, + 'data_stream.dataset', + safeLoad, + 'input' + ); + + expect(res).toEqual(null); + }); + + it('should not return an error message if the package is not input type', () => { + const res = validatePackagePolicyConfig( + { + type: 'text', + value: { dataset: 'Test', package: 'log' }, + }, + { + name: 'data_stream.dataset', + type: 'text', + }, + 'data_stream.dataset', + safeLoad, + 'integration' + ); + + expect(res).toEqual(null); + }); + + it('should not return an error message if the var is not dataset', () => { + const res = validatePackagePolicyConfig( + { + type: 'text', + value: { dataset: 'Test', package: 'log' }, + }, + { + name: 'test_field', + type: 'text', + }, + 'test_field', + safeLoad, + 'input' + ); + + expect(res).toEqual(null); + }); + + it('should return an error message if the string dataset value has special characters', () => { + const res = validatePackagePolicyConfig( + { + type: 'text', + value: 'test*', + }, + { + name: 'data_stream.dataset', + type: 'text', + }, + 'data_stream.dataset', + safeLoad, + 'input' + ); + + expect(res).toEqual(['Dataset contains invalid characters']); + }); + + it('should return an error message if the dataset value has special characters', () => { + const res = validatePackagePolicyConfig( + { + type: 'text', + value: { dataset: 'test*', package: 'log' }, + }, + { + name: 'data_stream.dataset', + type: 'text', + }, + 'data_stream.dataset', + safeLoad, + 'input' + ); + + expect(res).toEqual(['Dataset contains invalid characters']); + }); + }); }); diff --git a/x-pack/plugins/fleet/common/services/validate_package_policy.ts b/x-pack/plugins/fleet/common/services/validate_package_policy.ts index 8cbaf56b546db..1de38822cbc80 100644 --- a/x-pack/plugins/fleet/common/services/validate_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/validate_package_policy.ts @@ -19,6 +19,8 @@ import type { RegistryVarsEntry, } from '../types'; +import { DATASET_VAR_NAME } from '../constants'; + import { isValidNamespace, doesPackageHaveIntegrations, @@ -26,6 +28,7 @@ import { getNormalizedDataStreams, } from '.'; import { packageHasNoPolicyTemplates } from './policy_template'; +import { isValidDataset } from './is_valid_namespace'; type Errors = string[] | null; @@ -173,7 +176,13 @@ export const validatePackagePolicy = ( results[name] = input.enabled && stream.enabled - ? validatePackagePolicyConfig(configEntry, streamVarDefs[name], name, safeLoadYaml) + ? validatePackagePolicyConfig( + configEntry, + streamVarDefs[name], + name, + safeLoadYaml, + packageInfo.type + ) : null; return results; @@ -202,7 +211,8 @@ export const validatePackagePolicyConfig = ( configEntry: PackagePolicyConfigRecordEntry | undefined, varDef: RegistryVarsEntry, varName: string, - safeLoadYaml: (yaml: string) => any + safeLoadYaml: (yaml: string) => any, + packageType?: string ): string[] | null => { const errors = []; @@ -357,6 +367,16 @@ export const validatePackagePolicyConfig = ( } } + if (varName === DATASET_VAR_NAME && packageType === 'input' && parsedValue !== undefined) { + const { valid, error } = isValidDataset( + parsedValue.dataset ? parsedValue.dataset : parsedValue, + false + ); + if (!valid && error) { + errors.push(error); + } + } + return errors.length ? errors : null; }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_combo.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_combo.tsx deleted file mode 100644 index 180060db52f1c..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_combo.tsx +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 React, { useEffect, useState } from 'react'; -import { EuiComboBox, EuiIcon, EuiLink, EuiSpacer, EuiText, EuiToolTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { FormattedMessage } from '@kbn/i18n-react'; - -import type { DataStream } from '../../../../../../../../../common/types'; -import { GENERIC_DATASET_NAME } from '../../../../../../../../../common/constants'; - -interface SelectedDataset { - dataset: string; - package: string; -} - -export const DatasetComboBox: React.FC<{ - value?: SelectedDataset | string; - onChange: (newValue: SelectedDataset) => void; - datastreams: DataStream[]; - pkgName?: string; - isDisabled?: boolean; -}> = ({ value, onChange, datastreams, isDisabled, pkgName = '' }) => { - const datasetOptions = - datastreams.map((datastream: DataStream) => ({ - label: datastream.dataset, - value: datastream, - })) ?? []; - const existingGenericStream = datasetOptions.find((ds) => ds.label === GENERIC_DATASET_NAME); - const valueAsOption = value - ? typeof value === 'string' - ? { label: value, value: { dataset: value, package: pkgName } } - : { label: value.dataset, value: { dataset: value.dataset, package: value.package } } - : undefined; - const defaultOption = valueAsOption || - existingGenericStream || { - label: GENERIC_DATASET_NAME, - value: { dataset: GENERIC_DATASET_NAME, package: pkgName }, - }; - - const [selectedOptions, setSelectedOptions] = useState>([defaultOption]); - - useEffect(() => { - if (!value || typeof value === 'string') onChange(defaultOption.value as SelectedDataset); - }, [value, defaultOption.value, onChange, pkgName]); - - const onDatasetChange = (newSelectedOptions: Array<{ label: string; value?: DataStream }>) => { - setSelectedOptions(newSelectedOptions); - const dataStream = newSelectedOptions[0].value; - onChange({ - dataset: newSelectedOptions[0].label, - package: !dataStream || typeof dataStream === 'string' ? pkgName : dataStream.package, - }); - }; - - const onCreateOption = (searchValue: string = '') => { - const normalizedSearchValue = searchValue.trim().toLowerCase(); - if (!normalizedSearchValue) { - return; - } - const newOption = { - label: searchValue, - value: { dataset: searchValue, package: pkgName }, - }; - setSelectedOptions([newOption]); - onChange({ - dataset: searchValue, - package: pkgName, - }); - }; - return ( - <> - - {valueAsOption && valueAsOption.value.package !== pkgName && ( - <> - - - -   - - } - > - - {i18n.translate('xpack.fleet.datasetCombo.learnMoreLink', { - defaultMessage: 'learn more', - })} - - - ), - }} - /> - - - )} - - ); -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.test.tsx new file mode 100644 index 0000000000000..e45da365e74aa --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.test.tsx @@ -0,0 +1,71 @@ +/* + * 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 React from 'react'; +import { fireEvent } from '@testing-library/react'; + +import { createFleetTestRendererMock } from '../../../../../../../../mock'; + +import { DatasetComponent } from './dataset_component'; + +describe('DatasetComponent', () => { + function render(value = 'generic', datastreams: any = []) { + const renderer = createFleetTestRendererMock(); + const mockOnChange = jest.fn(); + const fieldLabel = 'Dataset name'; + + const utils = renderer.render( + + ); + + return { utils, mockOnChange }; + } + + it('should show validation error if dataset is invalid', () => { + const { utils } = render(); + + const inputEl = utils.getByTestId('comboBoxSearchInput'); + fireEvent.change(inputEl, { target: { value: 'generic*' } }); + fireEvent.keyDown(inputEl, { key: 'Enter', code: 'Enter' }); + + utils.getByText('Dataset contains invalid characters'); + }); + + it('should not show validation error if dataset is valid', () => { + const { utils } = render(); + + const inputEl = utils.getByTestId('comboBoxSearchInput'); + fireEvent.change(inputEl, { target: { value: 'test' } }); + fireEvent.keyDown(inputEl, { key: 'Enter', code: 'Enter' }); + + expect(utils.queryByText('Dataset contains invalid characters')).toBeNull(); + }); + + it('should not show validation error if valid dataset selected from select', () => { + const { utils, mockOnChange } = render(undefined, [ + { dataset: 'fleet_server.test_ds', package: 'log' }, + ]); + + const inputEl = utils.getByTestId('comboBoxSearchInput'); + fireEvent.click(inputEl); + const option = utils.getByText('fleet_server.test_ds'); + fireEvent.click(option); + + expect(utils.queryByText('Dataset contains invalid characters')).toBeNull(); + expect(mockOnChange).toHaveBeenCalledWith({ dataset: 'fleet_server.test_ds', package: 'log' }); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.tsx new file mode 100644 index 0000000000000..bac9f76b5cf54 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/dataset_component.tsx @@ -0,0 +1,174 @@ +/* + * 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 React, { useEffect, useState } from 'react'; +import { + EuiComboBox, + EuiFormRow, + EuiIcon, + EuiLink, + EuiSpacer, + EuiText, + EuiToolTip, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import styled from 'styled-components'; +import ReactMarkdown from 'react-markdown'; + +import { FormattedMessage } from '@kbn/i18n-react'; + +import type { DataStream } from '../../../../../../../../../common/types'; +import { GENERIC_DATASET_NAME } from '../../../../../../../../../common/constants'; +import { isValidDataset } from '../../../../../../../../../common'; + +const FormRow = styled(EuiFormRow)` + .euiFormRow__label { + flex: 1; + } + + .euiFormRow__fieldWrapper > .euiPanel { + padding: ${(props) => props.theme.eui?.euiSizeXS}; + } +`; + +interface SelectedDataset { + dataset: string; + package: string; +} + +export const DatasetComponent: React.FC<{ + value?: SelectedDataset | string; + onChange: (newValue: SelectedDataset) => void; + datastreams: DataStream[]; + pkgName?: string; + isDisabled?: boolean; + fieldLabel: string; + description?: string; +}> = ({ value, onChange, datastreams, isDisabled, pkgName = '', fieldLabel, description }) => { + const datasetOptions = + datastreams.map((datastream: DataStream) => ({ + label: datastream.dataset, + value: datastream, + })) ?? []; + const existingGenericStream = datasetOptions.find((ds) => ds.label === GENERIC_DATASET_NAME); + const valueAsOption = value + ? typeof value === 'string' + ? { label: value, value: { dataset: value, package: pkgName } } + : { label: value.dataset, value: { dataset: value.dataset, package: value.package } } + : undefined; + const defaultOption = valueAsOption || + existingGenericStream || { + label: GENERIC_DATASET_NAME, + value: { dataset: GENERIC_DATASET_NAME, package: pkgName }, + }; + + const [selectedOptions, setSelectedOptions] = useState>([defaultOption]); + const [isInvalid, setIsInvalid] = useState(false); + const [error, setError] = useState(undefined); + + useEffect(() => { + if (!value || typeof value === 'string') onChange(defaultOption.value as SelectedDataset); + }, [value, defaultOption.value, onChange, pkgName]); + + const onDatasetChange = (newSelectedOptions: Array<{ label: string; value?: DataStream }>) => { + setSelectedOptions(newSelectedOptions); + const dataStream = newSelectedOptions[0].value; + const { valid, error: dsError } = isValidDataset(newSelectedOptions[0].label, false); + setIsInvalid(!valid); + setError(dsError); + onChange({ + dataset: newSelectedOptions[0].label, + package: !dataStream || typeof dataStream === 'string' ? pkgName : dataStream.package, + }); + }; + + const onCreateOption = (searchValue: string = '') => { + const normalizedSearchValue = searchValue.trim().toLowerCase(); + if (!normalizedSearchValue) { + return; + } + const newOption = { + label: searchValue, + value: { dataset: searchValue, package: pkgName }, + }; + setSelectedOptions([newOption]); + const { valid, error: dsError } = isValidDataset(searchValue, false); + setIsInvalid(!valid); + setError(dsError); + onChange({ + dataset: searchValue, + package: pkgName, + }); + }; + return ( + } + fullWidth + > + <> + + {valueAsOption && valueAsOption.value.package !== pkgName && ( + <> + + + +   + + } + > + + {i18n.translate('xpack.fleet.datasetCombo.learnMoreLink', { + defaultMessage: 'learn more', + })} + + + ), + }} + /> + + + )} + + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx index 9464d60402a1d..653986a7128de 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx @@ -36,7 +36,7 @@ import { DATASET_VAR_NAME } from '../../../../../../../../../common/constants'; import type { DataStream, RegistryVarsEntry } from '../../../../../../types'; import { MultiTextInput } from './multi_text_input'; -import { DatasetComboBox } from './dataset_combo'; +import { DatasetComponent } from './dataset_component'; const FixedHeightDiv = styled.div` height: 300px; @@ -88,7 +88,6 @@ export const PackagePolicyInputVarField: React.FunctionComponent { const fleetStatus = useFleetStatus(); - const [isDirty, setIsDirty] = useState(false); const { required, type, title, name, description } = varDef; const isInvalid = Boolean((isDirty || forceShowErrors) && !!varErrors?.length); @@ -101,6 +100,20 @@ export const PackagePolicyInputVarField: React.FunctionComponent + ); + } + let field: JSX.Element; if (useSecretsUi) { @@ -127,10 +140,6 @@ export const PackagePolicyInputVarField: React.FunctionComponent ); } - if (name === DATASET_VAR_NAME && packageType === 'input') { - return ( - - ); - } switch (type) { case 'textarea': return ( diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 2f0ab0b25c907..845fe18530a5a 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -18698,10 +18698,6 @@ "xpack.fleet.multiRowInput.addRow": "Ajouter une ligne", "xpack.fleet.multiRowInput.deleteButton": "Supprimer la ligne", "xpack.fleet.multiTextInput.addRow": "Ajouter une ligne", - "xpack.fleet.namespaceValidation.invalidCharactersErrorMessage": "L'espace de nom contient des caractères non valides", - "xpack.fleet.namespaceValidation.lowercaseErrorMessage": "L'espace de nom doit être en minuscules", - "xpack.fleet.namespaceValidation.requiredErrorMessage": "L'espace de nom est obligatoire", - "xpack.fleet.namespaceValidation.tooLongErrorMessage": "L'espace de nom ne peut pas dépasser 100 octets", "xpack.fleet.newEnrollmentKey.cancelButtonLabel": "Annuler", "xpack.fleet.newEnrollmentKey.helpText": "Un ID de jeton sera utilisé si ce champ est laissé vide.", "xpack.fleet.newEnrollmentKey.keyCreatedToasts": "Jeton d'enregistrement créé", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 6d9d12a3c36a5..351327102a5f1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18675,10 +18675,6 @@ "xpack.fleet.multiRowInput.addRow": "行の追加", "xpack.fleet.multiRowInput.deleteButton": "行の削除", "xpack.fleet.multiTextInput.addRow": "行の追加", - "xpack.fleet.namespaceValidation.invalidCharactersErrorMessage": "名前空間に無効な文字が含まれています", - "xpack.fleet.namespaceValidation.lowercaseErrorMessage": "名前空間は小文字で指定する必要があります", - "xpack.fleet.namespaceValidation.requiredErrorMessage": "名前空間は必須です", - "xpack.fleet.namespaceValidation.tooLongErrorMessage": "名前空間は100バイト以下でなければなりません", "xpack.fleet.newEnrollmentKey.cancelButtonLabel": "キャンセル", "xpack.fleet.newEnrollmentKey.helpText": "これを空にすると、トークンIDが使用されます。", "xpack.fleet.newEnrollmentKey.keyCreatedToasts": "登録トークンが作成されました", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 4e76adb30ab5f..69f740ad5ac0e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18704,10 +18704,6 @@ "xpack.fleet.multiRowInput.addRow": "添加行", "xpack.fleet.multiRowInput.deleteButton": "删除行", "xpack.fleet.multiTextInput.addRow": "添加行", - "xpack.fleet.namespaceValidation.invalidCharactersErrorMessage": "命名空间包含无效字符", - "xpack.fleet.namespaceValidation.lowercaseErrorMessage": "命名空间必须小写", - "xpack.fleet.namespaceValidation.requiredErrorMessage": "“命名空间”必填", - "xpack.fleet.namespaceValidation.tooLongErrorMessage": "命名空间不能超过 100 个字节", "xpack.fleet.newEnrollmentKey.cancelButtonLabel": "取消", "xpack.fleet.newEnrollmentKey.helpText": "此项留空时,将使用令牌 ID。", "xpack.fleet.newEnrollmentKey.keyCreatedToasts": "注册令牌已创建", diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/input_package_rollback.ts b/x-pack/test/fleet_api_integration/apis/package_policy/input_package_rollback.ts index 50c325dac22fb..f470b872a8e52 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/input_package_rollback.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/input_package_rollback.ts @@ -79,7 +79,7 @@ export default function (providerContext: FtrProviderContext) { .send(policy) .expect(expectStatusCode); - return res.body.item; + return expectStatusCode === 200 ? res.body.item : res; }; const createAgentPolicy = async (name = 'Input Package Test 3') => { @@ -117,7 +117,10 @@ export default function (providerContext: FtrProviderContext) { setupFleetAndAgents(providerContext); it('should rollback package install on package policy create failure', async () => { - await createPackagePolicyWithDataset(agentPolicyId, 'test*', 400); + const res = await createPackagePolicyWithDataset(agentPolicyId, 'test*', 400); + expect(res.body.message).to.eql( + 'Package policy is invalid: inputs.logfile.streams.input_package_upgrade.logs.vars.data_stream.dataset: Dataset contains invalid characters' + ); const pkg = await getPackage(PACKAGE_NAME, START_VERSION); expect(pkg?.status).to.eql('not_installed');