mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[D4C] Policy UI can now validate string values by regex patterns (#153712)
## Summary Also includes updates to policy from cloud-defend repo. ### Checklist - [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 tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) docker) --------- Co-authored-by: sec_cloudnative_integrations <sec-cloudnative-integrations@elastic.co> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
b84972fb36
commit
0181b873fc
5 changed files with 80 additions and 12 deletions
|
@ -116,6 +116,22 @@ export const name = i18n.translate('xpack.cloudDefend.name', {
|
|||
defaultMessage: 'Name',
|
||||
});
|
||||
|
||||
export const errorInvalidResourceLabel = i18n.translate(
|
||||
'xpack.cloudDefend.errorInvalidResourceLabel',
|
||||
{
|
||||
defaultMessage:
|
||||
'"Orchestrator resource label" values must have the format: "key:value". A wildcard "*" can be used at the end of the value. e.g. "key:val*". To match on an empty label value, use "key:".',
|
||||
}
|
||||
);
|
||||
|
||||
export const errorInvalidFullContainerImageName = i18n.translate(
|
||||
'xpack.cloudDefend.errorInvalidFullContainerImageName',
|
||||
{
|
||||
defaultMessage:
|
||||
'"Full container image name" values must be in the format: image_repo/image_name e.g. "docker.io/nginx"',
|
||||
}
|
||||
);
|
||||
|
||||
export const errorConditionRequired = i18n.translate('xpack.cloudDefend.errorConditionRequired', {
|
||||
defaultMessage: 'At least one condition per selector is required.',
|
||||
});
|
||||
|
|
|
@ -215,6 +215,33 @@ describe('<ControlGeneralViewSelector />', () => {
|
|||
expect(getByText(i18n.errorValueLengthExceeded)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('shows an error if condition values fail their pattern regex', async () => {
|
||||
const { getByText, getByTestId, rerender } = render(<WrappedComponent />);
|
||||
|
||||
const addConditionBtn = getByTestId('cloud-defend-btnaddselectorcondition');
|
||||
addConditionBtn.click();
|
||||
|
||||
await waitFor(() => getByText('Container image name').click()); // add containerImageName
|
||||
|
||||
const updatedSelector: Selector = onChange.mock.calls[0][0];
|
||||
|
||||
rerender(<WrappedComponent selector={updatedSelector} />);
|
||||
|
||||
const el = getByTestId('cloud-defend-selectorcondition-containerImageName').querySelector(
|
||||
'input'
|
||||
);
|
||||
|
||||
if (el) {
|
||||
userEvent.type(el, 'bad*imagename{enter}');
|
||||
} else {
|
||||
throw new Error("Can't find input");
|
||||
}
|
||||
|
||||
const expectedError = '"containerImageName" values must match the pattern: /^[a-z0-9]+$/';
|
||||
|
||||
expect(getByText(expectedError)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('allows the user to remove conditions', async () => {
|
||||
const selector: Selector = {
|
||||
type: 'file',
|
||||
|
|
|
@ -25,6 +25,7 @@ import {
|
|||
EuiText,
|
||||
EuiCheckbox,
|
||||
} from '@elastic/eui';
|
||||
import { i18n as i18nLib } from '@kbn/i18n';
|
||||
import { useStyles } from './styles';
|
||||
import {
|
||||
ControlGeneralViewSelectorDeps,
|
||||
|
@ -48,6 +49,8 @@ import {
|
|||
MAX_FILE_PATH_VALUE_LENGTH_BYTES,
|
||||
} from '../../common/constants';
|
||||
|
||||
const { translate } = i18nLib;
|
||||
|
||||
interface ConditionProps {
|
||||
label: string;
|
||||
prop: SelectorCondition;
|
||||
|
@ -287,10 +290,23 @@ export const ControlGeneralViewSelector = ({
|
|||
errors.push(i18n.errorValueRequired);
|
||||
}
|
||||
|
||||
const { pattern, patternError } = SelectorConditionsMap[prop];
|
||||
|
||||
values.forEach((value) => {
|
||||
const bytes = new Blob([value]).size;
|
||||
|
||||
if (prop === 'targetFilePath') {
|
||||
if (pattern && !new RegExp(pattern).test(value)) {
|
||||
if (patternError) {
|
||||
errors.push(patternError);
|
||||
} else {
|
||||
errors.push(
|
||||
translate('xpack.cloudDefend.errorGenericRegexFailure', {
|
||||
defaultMessage: '"{prop}" values must match the pattern: /{pattern}/',
|
||||
values: { prop, pattern },
|
||||
})
|
||||
);
|
||||
}
|
||||
} else if (prop === 'targetFilePath') {
|
||||
if (bytes > MAX_FILE_PATH_VALUE_LENGTH_BYTES) {
|
||||
errors.push(i18n.errorValueLengthExceeded);
|
||||
}
|
||||
|
|
|
@ -154,7 +154,8 @@
|
|||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"pattern": "^([a-zA-Z0-9\\.\\-]+\\/)?[a-zA-Z0-9\\.\\-]+:[a-zA-Z0-9\\.\\-\\_]*\\*?$"
|
||||
}
|
||||
},
|
||||
"orchestratorResourceName": {
|
||||
|
@ -326,7 +327,8 @@
|
|||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"pattern": "^([a-zA-Z0-9\\.\\-]+\\/)?[a-zA-Z0-9\\.\\-]+:[a-zA-Z0-9\\.\\-\\_]*\\*?$"
|
||||
}
|
||||
},
|
||||
"orchestratorResourceName": {
|
||||
|
@ -371,13 +373,6 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"processUserName": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"processUserId": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
|
|
|
@ -15,6 +15,7 @@ import type {
|
|||
} from '@kbn/usage-collection-plugin/public';
|
||||
import type { CloudDefendRouterProps } from './application/router';
|
||||
import type { CloudDefendPageId } from './common/navigation/types';
|
||||
import * as i18n from './components/control_general_view/translations';
|
||||
|
||||
/**
|
||||
* cloud_defend plugin types
|
||||
|
@ -85,6 +86,8 @@ export type SelectorCondition =
|
|||
|
||||
export interface SelectorConditionOptions {
|
||||
type: SelectorConditionType;
|
||||
pattern?: string;
|
||||
patternError?: string;
|
||||
selectorType?: SelectorType;
|
||||
not?: SelectorCondition[];
|
||||
values?:
|
||||
|
@ -101,16 +104,27 @@ export type SelectorConditionsMapProps = {
|
|||
|
||||
// used to determine UX control and allowed values for each condition
|
||||
export const SelectorConditionsMap: SelectorConditionsMapProps = {
|
||||
containerImageName: { type: 'stringArray', not: ['fullContainerImageName'] },
|
||||
containerImageName: {
|
||||
type: 'stringArray',
|
||||
pattern: '^[a-z0-9]+$',
|
||||
not: ['fullContainerImageName'],
|
||||
},
|
||||
containerImageTag: { type: 'stringArray' },
|
||||
fullContainerImageName: {
|
||||
type: 'stringArray',
|
||||
pattern:
|
||||
'^(?:\\[[a-fA-F0-9:]+\\]|(?:[a-zA-Z0-9-](?:\\.[a-z0-9]+)*)+)(?::[0-9]+)?(?:\\/[a-z0-9]+)+$',
|
||||
patternError: i18n.errorInvalidFullContainerImageName,
|
||||
not: ['containerImageName'],
|
||||
},
|
||||
orchestratorClusterId: { type: 'stringArray' },
|
||||
orchestratorClusterName: { type: 'stringArray' },
|
||||
orchestratorNamespace: { type: 'stringArray' },
|
||||
orchestratorResourceLabel: { type: 'stringArray' },
|
||||
orchestratorResourceLabel: {
|
||||
type: 'stringArray',
|
||||
pattern: '^([a-zA-Z0-9\\.\\-]+\\/)?[a-zA-Z0-9\\.\\-]+:[a-zA-Z0-9\\.\\-\\_]*\\*?$',
|
||||
patternError: i18n.errorInvalidResourceLabel,
|
||||
},
|
||||
orchestratorResourceName: { type: 'stringArray' },
|
||||
orchestratorResourceType: { type: 'stringArray', values: ['node', 'pod'] },
|
||||
orchestratorType: { type: 'stringArray', values: ['kubernetes'] },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue