Skip to content

Commit

Permalink
[Ingest Manager] Add namespace validation (#75381)
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
  • Loading branch information
jen-huang authored Aug 20, 2020
1 parent 5308cc7 commit 3201efe
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 { storedPackagePoliciesToAgentInputs } from './package_policies_to_agent_
export { fullAgentPolicyToYaml } from './full_agent_policy_to_yaml';
export { isPackageLimited, doesAgentPolicyAlreadyIncludePackage } 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 { NewAgentPolicy, AgentPolicy } from '../../../types';
import { isValidNamespace } from '../../../services';
import { AgentPolicyDeleteProvider } from './agent_policy_delete_provider';

interface ValidationResults {
Expand Down Expand Up @@ -57,6 +58,13 @@ export const agentPolicyFormValidation = (
defaultMessage="A namespace is required"
/>,
];
} else if (!isValidNamespace(agentPolicy.namespace)) {
errors.namespace = [
<FormattedMessage
id="xpack.ingestManager.agentPolicyForm.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 {
NewPackagePolicy,
PackagePolicyInput,
Expand Down Expand Up @@ -65,6 +65,12 @@ export const validatePackagePolicy = (
defaultMessage: 'Namespace is required',
}),
];
} else if (!isValidNamespace(packagePolicy.namespace)) {
validationResults.namespace = [
i18n.translate('xpack.ingestManager.packagePolicyValidation.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 {
fullAgentPolicyToYaml,
isPackageLimited,
doesAgentPolicyAlreadyIncludePackage,
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 { PackagePolicySchema } from './package_policy';
import { PackagePolicySchema, NamespaceSchema } from './package_policy';
import { AgentPolicyStatus } from '../../../common';

const AgentPolicyBaseSchema = {
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 PackagePolicyBaseSchema = {
name: schema.string(),
description: schema.maybe(schema.string()),
namespace: schema.string({ minLength: 1 }),
namespace: NamespaceSchema,
policy_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_policies`)
.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_policies`)
.set('kbn-xsrf', 'xxxx')
.send({
name: 'TEST',
namespace: 'InvalidNamespace',
})
.expect(400);
});
});

describe('POST /api/ingest_manager/agent_policies/{agentPolicyId}/copy', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,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_policies`)
Expand All @@ -84,6 +84,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_policies`)
.set('kbn-xsrf', 'xxxx')
.send({
name: 'filetest-1',
description: '',
namespace: 'InvalidNamespace',
policy_id: agentPolicyId,
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 policy', async function () {
if (server.enabled) {
await supertest
Expand Down

0 comments on commit 3201efe

Please sign in to comment.