Skip to content

Commit

Permalink
[EDR Workflows] Fix field validation issue in Osquery Response Action…
Browse files Browse the repository at this point in the history
…s form (#171978)
  • Loading branch information
tomsonpl authored Nov 30, 2023
1 parent 25177aa commit cf996b8
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
packFixture,
} from '../../tasks/api_fixtures';
import {
RESPONSE_ACTIONS_ERRORS,
OSQUERY_RESPONSE_ACTION_ADD_BUTTON,
RESPONSE_ACTIONS_ITEM_0,
RESPONSE_ACTIONS_ITEM_1,
Expand Down Expand Up @@ -66,6 +67,48 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.contains('Response actions are run on each rule execution.');
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();

cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => {
cy.contains('Query is a required field');
cy.contains('Timeout value must be greater than 60 seconds.').should('not.exist');
});

// check if changing error state of one input doesn't clear other errors - START
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains('Advanced').click();
cy.getBySel('timeout-input').clear();
cy.contains('Timeout value must be greater than 60 seconds.');
});

cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => {
cy.contains('Query is a required field');
cy.contains('Timeout value must be greater than 60 seconds.');
});

cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.getBySel('timeout-input').type('6');
cy.contains('Timeout value must be greater than 60 seconds.');
});
cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => {
cy.contains('Query is a required field');
cy.contains('Timeout value must be greater than 60 seconds.');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.getBySel('timeout-input').type('6');
cy.contains('Timeout value must be greater than 60 seconds.').should('not.exist');
});
cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => {
cy.contains('Query is a required field');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.getBySel('timeout-input').type('6');
});
cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => {
cy.contains('Query is a required field');
cy.contains('Timeout value must be greater than 60 seconds.').should('not.exist');
});
// check if changing error state of one input doesn't clear other errors - END

cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains('Query is a required field');
inputQuery('select * from uptime1');
Expand All @@ -74,7 +117,7 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('Run a set of queries in a pack').click();
});
cy.getBySel('response-actions-error')
cy.getBySel(RESPONSE_ACTIONS_ERRORS)
.within(() => {
cy.contains('Pack is a required field');
})
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ describe('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => {
cy.contains('Query is a required field').should('not.exist');
checkResults();
getAdvancedButton().click();
fillInQueryTimeout('91');
fillInQueryTimeout('910');
submitQuery();
cy.contains('Timeout value must be lower than 900 seconds.');
fillInQueryTimeout('89');
fillInQueryTimeout('890');
submitQuery();
cy.contains('Timeout value must be lower than 900 seconds.').should('not.exist');
typeInOsqueryFieldInput('days{downArrow}{enter}');
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/osquery/cypress/tasks/response_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ServerlessRoleName } from '../support/roles';
import { cleanupRule, loadRule } from './api_fixtures';
import { closeDateTabIfVisible } from './integrations';

export const RESPONSE_ACTIONS_ERRORS = 'response-actions-error';
export const RESPONSE_ACTIONS_ITEM_0 = 'response-actions-list-item-0';
export const RESPONSE_ACTIONS_ITEM_1 = 'response-actions-list-item-1';
export const RESPONSE_ACTIONS_ITEM_2 = 'response-actions-list-item-2';
Expand Down
38 changes: 17 additions & 21 deletions x-pack/plugins/osquery/public/form/timeout_field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,12 @@
import React, { useCallback, useMemo } from 'react';
import deepEqual from 'fast-deep-equal';
import { useController } from 'react-hook-form';
import type { EuiFieldNumberProps } from '@elastic/eui';
import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';

import { QUERY_TIMEOUT } from '../../common/constants';

const timeoutFieldValidations = {
min: {
message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMinNumberError', {
defaultMessage: 'Timeout value must be greater than {than} seconds.',
values: { than: QUERY_TIMEOUT.DEFAULT },
}),
value: QUERY_TIMEOUT.DEFAULT,
},
max: {
message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMaxNumberError', {
defaultMessage: 'Timeout value must be lower than {than} seconds.',
values: { than: QUERY_TIMEOUT.MAX },
}),
value: QUERY_TIMEOUT.MAX,
},
};

interface TimeoutFieldProps {
euiFieldProps?: Record<string, unknown>;
}
Expand All @@ -43,12 +25,26 @@ const TimeoutFieldComponent = ({ euiFieldProps }: TimeoutFieldProps) => {
name: 'timeout',
defaultValue: QUERY_TIMEOUT.DEFAULT,
rules: {
...timeoutFieldValidations,
validate: (currentValue: number) => {
if (currentValue < QUERY_TIMEOUT.DEFAULT || isNaN(currentValue)) {
return i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMinNumberError', {
defaultMessage: 'Timeout value must be greater than {than} seconds.',
values: { than: QUERY_TIMEOUT.DEFAULT },
});
}

if (currentValue > QUERY_TIMEOUT.MAX) {
return i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMaxNumberError', {
defaultMessage: 'Timeout value must be lower than {than} seconds.',
values: { than: QUERY_TIMEOUT.MAX },
});
}
},
},
});
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const numberValue = e.target.valueAsNumber ? e.target.valueAsNumber : 0;
const numberValue = parseInt(e.target.value, 10);
onChange(numberValue);
},
[onChange]
Expand Down Expand Up @@ -77,7 +73,7 @@ const TimeoutFieldComponent = ({ euiFieldProps }: TimeoutFieldProps) => {
>
<EuiFieldNumber
isInvalid={hasError}
value={value as EuiFieldNumberProps['value']}
value={value}
onChange={handleChange}
fullWidth
type="number"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import React, { useCallback, useMemo } from 'react';
import { isEmpty, map } from 'lodash';
import { useFormContext } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { useKibana } from '../../../common/lib/kibana';

export const ResponseActionFormField = React.memo(({ field }: { field: FieldHook }) => {
const { setErrors, clearErrors, value, setValue } = field;
const { clearErrors, value, setValue, path } = field;
const { osquery } = useKibana().services;
const context = useFormContext();

const OsqueryForm = useMemo(
() => osquery?.OsqueryResponseActionTypeForm,
Expand All @@ -24,10 +26,11 @@ export const ResponseActionFormField = React.memo(({ field }: { field: FieldHook
if (isEmpty(newErrors)) {
clearErrors();
} else {
setErrors(map(newErrors, (error) => ({ message: error.message })));
const errors = map(newErrors, (error) => ({ message: error.message }));
context.setFieldErrors(path, errors);
}
},
[setErrors, clearErrors]
[clearErrors, context, path]
);

// @ts-expect-error update types
Expand Down

0 comments on commit cf996b8

Please sign in to comment.