[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:
Karl Godard 2023-03-27 15:26:00 -07:00 committed by GitHub
parent b84972fb36
commit 0181b873fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 12 deletions

View file

@ -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.',
});

View file

@ -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',

View 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);
}

View file

@ -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,

View file

@ -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'] },