Skip to content

Commit

Permalink
[Ingest Manager] Add namespace validation (#75381) (#75612)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jen-huang authored Aug 21, 2020
1 parent bb06629 commit 21a13ad
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 6 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/ingest_manager/common/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Original file line number Diff line number Diff line change
@@ -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<bar')).toBe(false);
expect(isValidNamespace('foo|bar')).toBe(false);
expect(isValidNamespace('foo,bar')).toBe(false);
expect(isValidNamespace('foo#bar')).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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.
*/

// Namespace string eventually becomes part of an index name. This method partially implements index name rules from
// https://github.com/elastic/elasticsearch/blob/master/docs/reference/indices/create-index.asciidoc
export function isValidNamespace(namespace: string) {
return (
typeof namespace === 'string' &&
// Lowercase only
namespace === namespace.toLowerCase() &&
// Cannot include \, /, *, ?, ", <, >, |, space character, comma, #, :
/^[^\*\\/\?"<>|\s,#:]+$/.test(namespace)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -57,6 +58,13 @@ export const agentConfigFormValidation = (
defaultMessage="A namespace is required"
/>,
];
} else if (!isValidNamespace(agentConfig.namespace)) {
errors.namespace = [
<FormattedMessage
id="xpack.ingestManager.agentConfigForm.namespaceInvalidErrorMessage"
defaultMessage="Namespace contains invalid characters"
/>,
];
}

return errors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ export {
configToYaml,
isPackageLimited,
doesAgentConfigAlreadyIncludePackage,
isValidNamespace,
} from '../../../../common';
Original file line number Diff line number Diff line change
Expand Up @@ -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')]))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand All @@ -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
Expand Down

0 comments on commit 21a13ad

Please sign in to comment.