mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 10:23:14 -04:00
* [Osquery] Fix ECS editor field array value (#132786)
(cherry picked from commit 272d9be670
)
* revert
This commit is contained in:
parent
8a40536c61
commit
0b6a03355b
14 changed files with 61 additions and 56 deletions
|
@ -79,7 +79,7 @@ describe('ALL - Add Integration', () => {
|
||||||
it.skip('should have integration and packs copied when upgrading integration', () => {
|
it.skip('should have integration and packs copied when upgrading integration', () => {
|
||||||
const packageName = 'osquery_manager';
|
const packageName = 'osquery_manager';
|
||||||
const oldVersion = '1.2.0';
|
const oldVersion = '1.2.0';
|
||||||
const newVersion = '1.3.0';
|
const newVersion = '1.3.1';
|
||||||
|
|
||||||
cy.visit(`app/integrations/detail/${packageName}-${oldVersion}/overview`);
|
cy.visit(`app/integrations/detail/${packageName}-${oldVersion}/overview`);
|
||||||
cy.contains('Add Osquery Manager').click();
|
cy.contains('Add Osquery Manager').click();
|
||||||
|
|
|
@ -17,7 +17,6 @@ import {
|
||||||
import { FormattedMessage } from '@kbn/i18n-react';
|
import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import deepMerge from 'deepmerge';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { pickBy, isEmpty, map } from 'lodash';
|
import { pickBy, isEmpty, map } from 'lodash';
|
||||||
|
@ -110,8 +109,12 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
|
||||||
options: {
|
options: {
|
||||||
stripEmptyFields: false,
|
stripEmptyFields: false,
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
serializer: ({
|
||||||
serializer: ({ savedQueryId, ecs_mapping, ...formData }) =>
|
savedQueryId,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
ecs_mapping,
|
||||||
|
...formData
|
||||||
|
}) =>
|
||||||
pickBy(
|
pickBy(
|
||||||
{
|
{
|
||||||
...formData,
|
...formData,
|
||||||
|
@ -120,20 +123,6 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
|
||||||
},
|
},
|
||||||
(value) => !isEmpty(value)
|
(value) => !isEmpty(value)
|
||||||
),
|
),
|
||||||
defaultValue: deepMerge(
|
|
||||||
{
|
|
||||||
agentSelection: {
|
|
||||||
agents: [],
|
|
||||||
allAgentsSelected: false,
|
|
||||||
platformsSelected: [],
|
|
||||||
policiesSelected: [],
|
|
||||||
},
|
|
||||||
query: '',
|
|
||||||
savedQueryId: null,
|
|
||||||
ecs_mapping: [],
|
|
||||||
},
|
|
||||||
defaultValue ?? {}
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { updateFieldValues, setFieldValue, submit, isSubmitting } = form;
|
const { updateFieldValues, setFieldValue, submit, isSubmitting } = form;
|
||||||
|
@ -256,6 +245,7 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<UseField path="savedQueryId" component={GhostFormField} />
|
||||||
<UseField
|
<UseField
|
||||||
path="query"
|
path="query"
|
||||||
component={LiveQueryQueryField}
|
component={LiveQueryQueryField}
|
||||||
|
@ -385,7 +375,6 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
|
||||||
<EuiFlexItem>{queryFieldStepContent}</EuiFlexItem>
|
<EuiFlexItem>{queryFieldStepContent}</EuiFlexItem>
|
||||||
<EuiFlexItem>{resultsStepContent}</EuiFlexItem>
|
<EuiFlexItem>{resultsStepContent}</EuiFlexItem>
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
<UseField path="savedQueryId" component={GhostFormField} />
|
|
||||||
</Form>
|
</Form>
|
||||||
{showSavedQueryFlyout ? (
|
{showSavedQueryFlyout ? (
|
||||||
<SavedQueryFlyout
|
<SavedQueryFlyout
|
||||||
|
|
|
@ -28,6 +28,7 @@ export const liveQueryFormSchema = {
|
||||||
validations: [],
|
validations: [],
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
|
defaultValue: '',
|
||||||
type: FIELD_TYPES.TEXT,
|
type: FIELD_TYPES.TEXT,
|
||||||
validations: [
|
validations: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -143,7 +143,7 @@ const QueriesFieldComponent: React.FC<QueriesFieldProps> = ({
|
||||||
pickBy(
|
pickBy(
|
||||||
{
|
{
|
||||||
id: newQueryId,
|
id: newQueryId,
|
||||||
interval: newQuery.interval ?? parsedContent.interval,
|
interval: newQuery.interval ?? parsedContent.interval ?? '3600',
|
||||||
query: newQuery.query,
|
query: newQuery.query,
|
||||||
version: newQuery.version ?? parsedContent.version,
|
version: newQuery.version ?? parsedContent.version,
|
||||||
platform: getSupportedPlatforms(newQuery.platform ?? parsedContent.platform),
|
platform: getSupportedPlatforms(newQuery.platform ?? parsedContent.platform),
|
||||||
|
|
|
@ -398,7 +398,7 @@ const OsqueryColumnFieldComponent: React.FC<OsqueryColumnFieldProps> = ({
|
||||||
return ecsKeySchemaOption?.value?.normalization !== 'array';
|
return ecsKeySchemaOption?.value?.normalization !== 'array';
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return !!ecsKey?.length;
|
||||||
}, [typeValue, formData, item.path]);
|
}, [typeValue, formData, item.path]);
|
||||||
|
|
||||||
const onTypeChange = useCallback(
|
const onTypeChange = useCallback(
|
||||||
|
@ -637,6 +637,7 @@ export const ECSMappingEditorForm: React.FC<ECSMappingEditorFormProps> = ({
|
||||||
osquerySchemaOptions,
|
osquerySchemaOptions,
|
||||||
editForm: !isLastItem,
|
editForm: !isLastItem,
|
||||||
},
|
},
|
||||||
|
readDefaultValueOnForm: !item.isNew,
|
||||||
config: {
|
config: {
|
||||||
valueChangeDebounceTime: 300,
|
valueChangeDebounceTime: 300,
|
||||||
type: FIELD_TYPES.COMBO_BOX,
|
type: FIELD_TYPES.COMBO_BOX,
|
||||||
|
@ -702,6 +703,7 @@ export const ECSMappingEditorForm: React.FC<ECSMappingEditorFormProps> = ({
|
||||||
component={ECSComboboxField}
|
component={ECSComboboxField}
|
||||||
euiFieldProps={ecsComboBoxEuiFieldProps}
|
euiFieldProps={ecsComboBoxEuiFieldProps}
|
||||||
validationData={validationData}
|
validationData={validationData}
|
||||||
|
readDefaultValueOnForm={!item.isNew}
|
||||||
// @ts-expect-error update types
|
// @ts-expect-error update types
|
||||||
config={config}
|
config={config}
|
||||||
/>
|
/>
|
||||||
|
@ -1017,7 +1019,9 @@ export const ECSMappingEditorField = React.memo(
|
||||||
if (itemKey) {
|
if (itemKey) {
|
||||||
const serializedFormData = formDataSerializer();
|
const serializedFormData = formDataSerializer();
|
||||||
const itemValue =
|
const itemValue =
|
||||||
serializedFormData.ecs_mapping && serializedFormData.ecs_mapping[`${itemKey}`]?.field;
|
serializedFormData.ecs_mapping &&
|
||||||
|
(serializedFormData.ecs_mapping[`${itemKey}`]?.field ||
|
||||||
|
serializedFormData.ecs_mapping[`${itemKey}`]?.value);
|
||||||
|
|
||||||
if (itemValue && onAdd.current) {
|
if (itemValue && onAdd.current) {
|
||||||
onAdd.current();
|
onAdd.current();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EuiIcon } from '@elastic/eui';
|
import { EuiIcon } from '@elastic/eui';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { getPlatformIconModule } from './helpers';
|
import { getPlatformIconModule } from './helpers';
|
||||||
|
|
||||||
export interface PlatformIconProps {
|
export interface PlatformIconProps {
|
||||||
|
@ -14,19 +14,9 @@ export interface PlatformIconProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlatformIconComponent: React.FC<PlatformIconProps> = ({ platform }) => {
|
const PlatformIconComponent: React.FC<PlatformIconProps> = ({ platform }) => {
|
||||||
const [Icon, setIcon] = useState<React.ReactElement | null>(null);
|
const platformIconModule = useMemo(() => getPlatformIconModule(platform), [platform]);
|
||||||
|
|
||||||
// FIXME: This is a hack to force the icon to be loaded asynchronously.
|
return <EuiIcon type={platformIconModule} title={platform} size="l" />;
|
||||||
useEffect(() => {
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
const platformIconModule = getPlatformIconModule(platform);
|
|
||||||
setIcon(<EuiIcon type={platformIconModule} title={platform} size="l" />);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, [platform, setIcon]);
|
|
||||||
|
|
||||||
return Icon;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PlatformIcon = React.memo(PlatformIconComponent);
|
export const PlatformIcon = React.memo(PlatformIconComponent);
|
||||||
|
|
|
@ -30,6 +30,7 @@ import { ALL_OSQUERY_VERSIONS_OPTIONS } from './constants';
|
||||||
import { UsePackQueryFormProps, PackFormData, usePackQueryForm } from './use_pack_query_form';
|
import { UsePackQueryFormProps, PackFormData, usePackQueryForm } from './use_pack_query_form';
|
||||||
import { SavedQueriesDropdown } from '../../saved_queries/saved_queries_dropdown';
|
import { SavedQueriesDropdown } from '../../saved_queries/saved_queries_dropdown';
|
||||||
import { ECSMappingEditorField } from './lazy_ecs_mapping_editor_field';
|
import { ECSMappingEditorField } from './lazy_ecs_mapping_editor_field';
|
||||||
|
import { useKibana } from '../../common/lib/kibana';
|
||||||
|
|
||||||
const CommonUseField = getUseField({ component: Field });
|
const CommonUseField = getUseField({ component: Field });
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ const QueryFlyoutComponent: React.FC<QueryFlyoutProps> = ({
|
||||||
onSave,
|
onSave,
|
||||||
onClose,
|
onClose,
|
||||||
}) => {
|
}) => {
|
||||||
|
const permissions = useKibana().services.application.capabilities.osquery;
|
||||||
const [isEditMode] = useState(!!defaultValue);
|
const [isEditMode] = useState(!!defaultValue);
|
||||||
const { form } = usePackQueryForm({
|
const { form } = usePackQueryForm({
|
||||||
uniqueQueryIds,
|
uniqueQueryIds,
|
||||||
|
@ -117,7 +119,7 @@ const QueryFlyoutComponent: React.FC<QueryFlyoutProps> = ({
|
||||||
</EuiFlyoutHeader>
|
</EuiFlyoutHeader>
|
||||||
<EuiFlyoutBody>
|
<EuiFlyoutBody>
|
||||||
<Form form={form}>
|
<Form form={form}>
|
||||||
{!isEditMode ? (
|
{!isEditMode && permissions.readSavedQueries ? (
|
||||||
<>
|
<>
|
||||||
<SavedQueriesDropdown onChange={handleSetQueryValue} />
|
<SavedQueriesDropdown onChange={handleSetQueryValue} />
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { FIELD_TYPES } from '../../shared_imports';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createIdFieldValidations,
|
createIdFieldValidations,
|
||||||
intervalFieldValidation,
|
intervalFieldValidations,
|
||||||
queryFieldValidation,
|
queryFieldValidation,
|
||||||
} from './validations';
|
} from './validations';
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export const createFormSchema = (ids: Set<string>) => ({
|
||||||
label: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel', {
|
label: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel', {
|
||||||
defaultMessage: 'Interval (s)',
|
defaultMessage: 'Interval (s)',
|
||||||
}),
|
}),
|
||||||
validations: [{ validator: intervalFieldValidation }],
|
validations: intervalFieldValidations,
|
||||||
},
|
},
|
||||||
platform: {
|
platform: {
|
||||||
type: FIELD_TYPES.TEXT,
|
type: FIELD_TYPES.TEXT,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
|
||||||
import { ValidationFunc, fieldValidators } from '../../shared_imports';
|
import { ValidationConfig, ValidationFunc, fieldValidators } from '../../shared_imports';
|
||||||
export { queryFieldValidation } from '../../common/validations';
|
export { queryFieldValidation } from '../../common/validations';
|
||||||
|
|
||||||
const idPattern = /^[a-zA-Z0-9-_]+$/;
|
const idPattern = /^[a-zA-Z0-9-_]+$/;
|
||||||
|
@ -48,14 +48,30 @@ export const createIdFieldValidations = (ids: Set<string>) => [
|
||||||
createUniqueIdValidation(ids),
|
createUniqueIdValidation(ids),
|
||||||
];
|
];
|
||||||
|
|
||||||
export const intervalFieldValidation: ValidationFunc<
|
export const intervalFieldValidations: Array<
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
ValidationConfig<
|
||||||
any,
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
string,
|
any,
|
||||||
number
|
string,
|
||||||
> = fieldValidators.numberGreaterThanField({
|
number
|
||||||
than: 0,
|
>
|
||||||
message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.invalidIntervalField', {
|
> = [
|
||||||
defaultMessage: 'A positive interval value is required',
|
{
|
||||||
}),
|
validator: fieldValidators.numberGreaterThanField({
|
||||||
});
|
than: 0,
|
||||||
|
message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldMinNumberError', {
|
||||||
|
defaultMessage: 'A positive interval value is required',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: fieldValidators.numberSmallerThanField({
|
||||||
|
than: 604800,
|
||||||
|
message: ({ than }) =>
|
||||||
|
i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldMaxNumberError', {
|
||||||
|
defaultMessage: 'An interval value must be lower than {than}',
|
||||||
|
values: { than },
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
|
@ -12,6 +12,7 @@ export type {
|
||||||
FormData,
|
FormData,
|
||||||
FormHook,
|
FormHook,
|
||||||
FormSchema,
|
FormSchema,
|
||||||
|
ValidationConfig,
|
||||||
ValidationError,
|
ValidationError,
|
||||||
ValidationFunc,
|
ValidationFunc,
|
||||||
ValidationFuncArg,
|
ValidationFuncArg,
|
||||||
|
|
|
@ -19,14 +19,16 @@ const getInstallation = async (osqueryContext: OsqueryAppContext) =>
|
||||||
|
|
||||||
export const getInstalledSavedQueriesMap = async (osqueryContext: OsqueryAppContext) => {
|
export const getInstalledSavedQueriesMap = async (osqueryContext: OsqueryAppContext) => {
|
||||||
const installation = await getInstallation(osqueryContext);
|
const installation = await getInstallation(osqueryContext);
|
||||||
|
|
||||||
if (installation) {
|
if (installation) {
|
||||||
return reduce(
|
return reduce<KibanaAssetReference, Record<string, KibanaAssetReference>>(
|
||||||
installation.installed_kibana,
|
installation.installed_kibana,
|
||||||
// @ts-expect-error not sure why it shouts, but still it's properly typed
|
(acc, item) => {
|
||||||
(acc: Record<string, KibanaAssetReference>, item: KibanaAssetReference) => {
|
|
||||||
if (item.type === savedQuerySavedObjectType) {
|
if (item.type === savedQuerySavedObjectType) {
|
||||||
return { ...acc, [item.id]: item };
|
return { ...acc, [item.id]: item };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
|
@ -21923,7 +21923,7 @@
|
||||||
"xpack.osquery.pack.queryFlyoutForm.idFieldLabel": "ID",
|
"xpack.osquery.pack.queryFlyoutForm.idFieldLabel": "ID",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel": "Intervalle (s)",
|
"xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel": "Intervalle (s)",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.invalidIdError": "Les caractères doivent être alphanumériques, _ ou -",
|
"xpack.osquery.pack.queryFlyoutForm.invalidIdError": "Les caractères doivent être alphanumériques, _ ou -",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.invalidIntervalField": "Une valeur d'intervalle positive est requise",
|
"xpack.osquery.pack.queryFlyoutForm.intervalFieldMinNumberError": "Une valeur d'intervalle positive est requise",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "Champ ECS",
|
"xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "Champ ECS",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "Valeur",
|
"xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "Valeur",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "Valeur obligatoire.",
|
"xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "Valeur obligatoire.",
|
||||||
|
|
|
@ -22061,7 +22061,7 @@
|
||||||
"xpack.osquery.pack.queryFlyoutForm.idFieldLabel": "ID",
|
"xpack.osquery.pack.queryFlyoutForm.idFieldLabel": "ID",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel": "間隔",
|
"xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel": "間隔",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.invalidIdError": "文字は英数字、_、または-でなければなりません",
|
"xpack.osquery.pack.queryFlyoutForm.invalidIdError": "文字は英数字、_、または-でなければなりません",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.invalidIntervalField": "正の間隔値が必要です",
|
"xpack.osquery.pack.queryFlyoutForm.intervalFieldMinNumberError": "正の間隔値が必要です",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "ECSフィールド",
|
"xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "ECSフィールド",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "値",
|
"xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "値",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "値が必要です。",
|
"xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "値が必要です。",
|
||||||
|
|
|
@ -22092,7 +22092,7 @@
|
||||||
"xpack.osquery.pack.queryFlyoutForm.idFieldLabel": "ID",
|
"xpack.osquery.pack.queryFlyoutForm.idFieldLabel": "ID",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel": "时间间隔 (s)",
|
"xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel": "时间间隔 (s)",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.invalidIdError": "字符必须是数字字母、_ 或 -",
|
"xpack.osquery.pack.queryFlyoutForm.invalidIdError": "字符必须是数字字母、_ 或 -",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.invalidIntervalField": "时间间隔值必须为正数",
|
"xpack.osquery.pack.queryFlyoutForm.intervalFieldMinNumberError": "时间间隔值必须为正数",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "ECS 字段",
|
"xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "ECS 字段",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "值",
|
"xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "值",
|
||||||
"xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "“值”必填。",
|
"xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "“值”必填。",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue