[Ingest Manager] Add namespace validation (#75381)
* Add namespace validation on APIs and UI * Add test coverage * Fix imports * Fix schema * Rename to policy * Fix typo
This commit is contained in:
parent
5308cc7100
commit
3201efe797
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
|
@ -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)
|
||||
);
|
||||
}
|
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
@ -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 (
|
||||
|
|
|
@ -24,4 +24,5 @@ export {
|
|||
fullAgentPolicyToYaml,
|
||||
isPackageLimited,
|
||||
doesAgentPolicyAlreadyIncludePackage,
|
||||
isValidNamespace,
|
||||
} from '../../../../common';
|
||||
|
|
|
@ -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')]))
|
||||
|
|
|
@ -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 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(
|
||||
|
|
|
@ -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')
|
||||
|
@ -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', () => {
|
||||
|
|
|
@ -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`)
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue