From 21a13adf78e4c323656b49eeccc21e9534048ecb Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 20 Aug 2020 17:24:22 -0700 Subject: [PATCH] [Ingest Manager] Add namespace validation (#75381) (#75612) * Add namespace validation on APIs and UI * Add test coverage * Fix imports * Fix schema * Rename to policy * Fix typo # Conflicts: # x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_form.tsx # x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts # x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts # x-pack/plugins/ingest_manager/server/types/models/agent_policy.ts # x-pack/plugins/ingest_manager/server/types/models/package_policy.ts # x-pack/test/ingest_manager_api_integration/apis/agent_policy/agent_policy.ts # x-pack/test/ingest_manager_api_integration/apis/package_policy/create.ts --- .../ingest_manager/common/services/index.ts | 1 + .../services/is_valid_namespace.test.ts | 28 +++++++++++++++++++ .../common/services/is_valid_namespace.ts | 17 +++++++++++ .../agent_config/components/config_form.tsx | 8 ++++++ .../services/validate_package_config.ts | 8 +++++- .../ingest_manager/services/index.ts | 1 + .../server/types/models/agent_config.ts | 4 +-- .../server/types/models/package_config.ts | 12 +++++++- .../apis/agent_config/agent_config.ts | 13 ++++++++- .../apis/package_config/create.ts | 27 +++++++++++++++++- 10 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/ingest_manager/common/services/is_valid_namespace.test.ts create mode 100644 x-pack/plugins/ingest_manager/common/services/is_valid_namespace.ts diff --git a/x-pack/plugins/ingest_manager/common/services/index.ts b/x-pack/plugins/ingest_manager/common/services/index.ts index 0c91dbbe10354..cfbde995f2ee3 100644 --- a/x-pack/plugins/ingest_manager/common/services/index.ts +++ b/x-pack/plugins/ingest_manager/common/services/index.ts @@ -10,3 +10,4 @@ export { storedPackageConfigsToAgentInputs } from './package_configs_to_agent_in export { configToYaml } from './config_to_yaml'; export { isPackageLimited, doesAgentConfigAlreadyIncludePackage } from './limited_package'; export { decodeCloudId } from './decode_cloud_id'; +export { isValidNamespace } from './is_valid_namespace'; diff --git a/x-pack/plugins/ingest_manager/common/services/is_valid_namespace.test.ts b/x-pack/plugins/ingest_manager/common/services/is_valid_namespace.test.ts new file mode 100644 index 0000000000000..40f37cc456f94 --- /dev/null +++ b/x-pack/plugins/ingest_manager/common/services/is_valid_namespace.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { isValidNamespace } from './is_valid_namespace'; + +describe('Ingest Manager - isValidNamespace', () => { + it('returns true for valid namespaces', () => { + expect(isValidNamespace('default')).toBe(true); + expect(isValidNamespace('namespace-with-dash')).toBe(true); + expect(isValidNamespace('123')).toBe(true); + }); + + it('returns false for invalid namespaces', () => { + expect(isValidNamespace('Default')).toBe(false); + expect(isValidNamespace('namespace with spaces')).toBe(false); + expect(isValidNamespace('foo/bar')).toBe(false); + expect(isValidNamespace('foo\\bar')).toBe(false); + expect(isValidNamespace('foo*bar')).toBe(false); + expect(isValidNamespace('foo?bar')).toBe(false); + expect(isValidNamespace('foo"bar')).toBe(false); + expect(isValidNamespace('foo, |, space character, comma, #, : + /^[^\*\\/\?"<>|\s,#:]+$/.test(namespace) + ); +} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/components/config_form.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/components/config_form.tsx index ad04e78bdcd11..5df8122a1fc90 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/components/config_form.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/components/config_form.tsx @@ -24,6 +24,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; import { NewAgentConfig, AgentConfig } from '../../../types'; +import { isValidNamespace } from '../../../services'; import { AgentConfigDeleteProvider } from './config_delete_provider'; interface ValidationResults { @@ -57,6 +58,13 @@ export const agentConfigFormValidation = ( defaultMessage="A namespace is required" />, ]; + } else if (!isValidNamespace(agentConfig.namespace)) { + errors.namespace = [ + , + ]; } return errors; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_package_config_page/services/validate_package_config.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_package_config_page/services/validate_package_config.ts index 0514ad574a8cd..96968d4729b82 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_package_config_page/services/validate_package_config.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_package_config_page/services/validate_package_config.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; import { safeLoad } from 'js-yaml'; -import { getFlattenedObject } from '../../../../services'; +import { getFlattenedObject, isValidNamespace } from '../../../../services'; import { NewPackageConfig, PackageConfigInput, @@ -65,6 +65,12 @@ export const validatePackageConfig = ( defaultMessage: 'Namespace is required', }), ]; + } else if (!isValidNamespace(packageConfig.namespace)) { + validationResults.namespace = [ + i18n.translate('xpack.ingestManager.packageConfigValidation.namespaceInvalidErrorMessage', { + defaultMessage: 'Namespace contains invalid characters', + }), + ]; } if ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts index 9c3b84d0835b8..fe98bb57c0d45 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts @@ -24,4 +24,5 @@ export { configToYaml, isPackageLimited, doesAgentConfigAlreadyIncludePackage, + isValidNamespace, } from '../../../../common'; diff --git a/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts b/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts index a9e14301cd7c3..7eca75b41a85e 100644 --- a/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts +++ b/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ import { schema } from '@kbn/config-schema'; -import { PackageConfigSchema } from './package_config'; +import { PackageConfigSchema, NamespaceSchema } from './package_config'; import { AgentConfigStatus } from '../../../common'; const AgentConfigBaseSchema = { name: schema.string({ minLength: 1 }), - namespace: schema.string({ minLength: 1 }), + namespace: NamespaceSchema, description: schema.maybe(schema.string()), monitoring_enabled: schema.maybe( schema.arrayOf(schema.oneOf([schema.literal('logs'), schema.literal('metrics')])) diff --git a/x-pack/plugins/ingest_manager/server/types/models/package_config.ts b/x-pack/plugins/ingest_manager/server/types/models/package_config.ts index 9b7ffb4f78175..070448f8a7a34 100644 --- a/x-pack/plugins/ingest_manager/server/types/models/package_config.ts +++ b/x-pack/plugins/ingest_manager/server/types/models/package_config.ts @@ -4,6 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ import { schema } from '@kbn/config-schema'; +import { isValidNamespace } from '../../../common'; + +export const NamespaceSchema = schema.string({ + minLength: 1, + validate: (value) => { + if (!isValidNamespace(value)) { + return 'Namespace contains invalid characters'; + } + }, +}); const ConfigRecordSchema = schema.recordOf( schema.string(), @@ -16,7 +26,7 @@ const ConfigRecordSchema = schema.recordOf( const PackageConfigBaseSchema = { name: schema.string(), description: schema.maybe(schema.string()), - namespace: schema.string({ minLength: 1 }), + namespace: NamespaceSchema, config_id: schema.string(), enabled: schema.boolean(), package: schema.maybe( diff --git a/x-pack/test/ingest_manager_api_integration/apis/agent_config/agent_config.ts b/x-pack/test/ingest_manager_api_integration/apis/agent_config/agent_config.ts index 89258600c85e1..a73f6417799e8 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/agent_config/agent_config.ts +++ b/x-pack/test/ingest_manager_api_integration/apis/agent_config/agent_config.ts @@ -26,7 +26,7 @@ export default function ({ getService }: FtrProviderContext) { expect(apiResponse.success).to.be(true); }); - it('should return a 400 with an invalid namespace', async () => { + it('should return a 400 with an empty namespace', async () => { await supertest .post(`/api/ingest_manager/agent_configs`) .set('kbn-xsrf', 'xxxx') @@ -36,6 +36,17 @@ export default function ({ getService }: FtrProviderContext) { }) .expect(400); }); + + it('should return a 400 with an invalid namespace', async () => { + await supertest + .post(`/api/ingest_manager/agent_configs`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'TEST', + namespace: 'InvalidNamespace', + }) + .expect(400); + }); }); describe('POST /api/ingest_manager/agent_configs/{agentConfigId}/copy', () => { diff --git a/x-pack/test/ingest_manager_api_integration/apis/package_config/create.ts b/x-pack/test/ingest_manager_api_integration/apis/package_config/create.ts index 7737a98163230..638630d145b7b 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/package_config/create.ts +++ b/x-pack/test/ingest_manager_api_integration/apis/package_config/create.ts @@ -61,7 +61,7 @@ export default function ({ getService }: FtrProviderContext) { } }); - it('should return a 400 with an invalid namespace', async function () { + it('should return a 400 with an empty namespace', async function () { if (server.enabled) { await supertest .post(`/api/ingest_manager/package_configs`) @@ -86,6 +86,31 @@ export default function ({ getService }: FtrProviderContext) { } }); + it('should return a 400 with an invalid namespace', async function () { + if (server.enabled) { + await supertest + .post(`/api/ingest_manager/package_configs`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'filetest-1', + description: '', + namespace: 'InvalidNamespace', + config_id: agentConfigId, + enabled: true, + output_id: '', + inputs: [], + package: { + name: 'filetest', + title: 'For File Tests', + version: '0.1.0', + }, + }) + .expect(400); + } else { + warnAndSkipTest(this, log); + } + }); + it('should not allow multiple limited packages on the same agent config', async function () { if (server.enabled) { await supertest