diff --git a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts index 8f1ece923f126..9d85a151efbbf 100644 --- a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts +++ b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts @@ -6,6 +6,7 @@ import { SavedObjectsServiceSetup, SavedObjectsType } from 'kibana/server'; import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; +import { migratePackagePolicyToV7110 } from '../../../security_solution/common'; import { OUTPUT_SAVED_OBJECT_TYPE, AGENT_POLICY_SAVED_OBJECT_TYPE, @@ -268,6 +269,7 @@ const getSavedObjectTypes = ( }, migrations: { '7.10.0': migratePackagePolicyToV7100, + '7.11.0': migratePackagePolicyToV7110, }, }, [PACKAGES_SAVED_OBJECT_TYPE]: { diff --git a/x-pack/plugins/security_solution/common/endpoint/models/policy_config.ts b/x-pack/plugins/security_solution/common/endpoint/models/policy_config.ts index 37b7308856196..3250e048edad2 100644 --- a/x-pack/plugins/security_solution/common/endpoint/models/policy_config.ts +++ b/x-pack/plugins/security_solution/common/endpoint/models/policy_config.ts @@ -24,6 +24,12 @@ export const factory = (): PolicyConfig => { malware: { mode: ProtectionModes.prevent, }, + popup: { + malware: { + message: '', + enabled: true, + }, + }, logging: { file: 'info', }, @@ -37,6 +43,12 @@ export const factory = (): PolicyConfig => { malware: { mode: ProtectionModes.prevent, }, + popup: { + malware: { + message: '', + enabled: true, + }, + }, logging: { file: 'info', }, diff --git a/x-pack/plugins/security_solution/common/endpoint/policy/migrations/to_v7_11.0.test.ts b/x-pack/plugins/security_solution/common/endpoint/policy/migrations/to_v7_11.0.test.ts new file mode 100644 index 0000000000000..33cf497e59311 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/policy/migrations/to_v7_11.0.test.ts @@ -0,0 +1,168 @@ +/* + * 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 { SavedObjectMigrationContext, SavedObjectUnsanitizedDoc } from 'kibana/server'; +import { PackagePolicy } from '../../../../../ingest_manager/common'; +import { migratePackagePolicyToV7110 } from './to_v7_11.0'; + +describe('7.11.0 Endpoint Package Policy migration', () => { + const migration = migratePackagePolicyToV7110; + it('adds malware notification checkbox and optional message', () => { + const doc: SavedObjectUnsanitizedDoc = { + attributes: { + name: 'Some Policy Name', + package: { + name: 'endpoint', + title: '', + version: '', + }, + id: 'endpoint', + policy_id: '', + enabled: true, + namespace: '', + output_id: '', + revision: 0, + updated_at: '', + updated_by: '', + created_at: '', + created_by: '', + inputs: [ + { + type: 'endpoint', + enabled: true, + streams: [], + config: { + policy: { + value: { + windows: {}, + mac: {}, + }, + }, + }, + }, + ], + }, + type: ' nested', + }; + + expect( + migration(doc, {} as SavedObjectMigrationContext) as SavedObjectUnsanitizedDoc + ).toEqual({ + attributes: { + name: 'Some Policy Name', + package: { + name: 'endpoint', + title: '', + version: '', + }, + id: 'endpoint', + policy_id: '', + enabled: true, + namespace: '', + output_id: '', + revision: 0, + updated_at: '', + updated_by: '', + created_at: '', + created_by: '', + inputs: [ + { + type: 'endpoint', + enabled: true, + streams: [], + config: { + policy: { + value: { + windows: { + popup: { + malware: { + message: '', + enabled: false, + }, + }, + }, + mac: { + popup: { + malware: { + message: '', + enabled: false, + }, + }, + }, + }, + }, + }, + }, + ], + }, + type: ' nested', + }); + }); + + it('does not modify non-endpoint package policies', () => { + const doc: SavedObjectUnsanitizedDoc = { + attributes: { + name: 'Some Policy Name', + package: { + name: 'notEndpoint', + title: '', + version: '', + }, + id: 'notEndpoint', + policy_id: '', + enabled: true, + namespace: '', + output_id: '', + revision: 0, + updated_at: '', + updated_by: '', + created_at: '', + created_by: '', + inputs: [ + { + type: 'notEndpoint', + enabled: true, + streams: [], + config: {}, + }, + ], + }, + type: ' nested', + }; + + expect( + migration(doc, {} as SavedObjectMigrationContext) as SavedObjectUnsanitizedDoc + ).toEqual({ + attributes: { + name: 'Some Policy Name', + package: { + name: 'notEndpoint', + title: '', + version: '', + }, + id: 'notEndpoint', + policy_id: '', + enabled: true, + namespace: '', + output_id: '', + revision: 0, + updated_at: '', + updated_by: '', + created_at: '', + created_by: '', + inputs: [ + { + type: 'notEndpoint', + enabled: true, + streams: [], + config: {}, + }, + ], + }, + type: ' nested', + }); + }); +}); diff --git a/x-pack/plugins/security_solution/common/endpoint/policy/migrations/to_v7_11.0.ts b/x-pack/plugins/security_solution/common/endpoint/policy/migrations/to_v7_11.0.ts new file mode 100644 index 0000000000000..8c2dabae21bbd --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/policy/migrations/to_v7_11.0.ts @@ -0,0 +1,32 @@ +/* + * 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 { SavedObjectMigrationFn, SavedObjectUnsanitizedDoc } from 'kibana/server'; +import { cloneDeep } from 'lodash'; +import { PackagePolicy } from '../../../../../ingest_manager/common'; + +export const migratePackagePolicyToV7110: SavedObjectMigrationFn = ( + packagePolicyDoc +) => { + const updatedPackagePolicyDoc: SavedObjectUnsanitizedDoc = cloneDeep( + packagePolicyDoc + ); + if (packagePolicyDoc.attributes.package?.name === 'endpoint') { + const input = updatedPackagePolicyDoc.attributes.inputs[0]; + const popup = { + malware: { + message: '', + enabled: false, + }, + }; + if (input && input.config) { + input.config.policy.value.windows.popup = popup; + input.config.policy.value.mac.popup = popup; + } + } + + return updatedPackagePolicyDoc; +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index f2033e064ef72..882b3e5182bf3 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -873,6 +873,12 @@ export interface PolicyConfig { logging: { file: string; }; + popup: { + malware: { + message: string; + enabled: boolean; + }; + }; }; mac: { events: { @@ -881,6 +887,12 @@ export interface PolicyConfig { network: boolean; }; malware: MalwareFields; + popup: { + malware: { + message: string; + enabled: boolean; + }; + }; logging: { file: string; }; @@ -904,11 +916,11 @@ export interface UIPolicyConfig { /** * Windows-specific policy configuration that is supported via the UI */ - windows: Pick; + windows: Pick; /** * Mac-specific policy configuration that is supported via the UI */ - mac: Pick; + mac: Pick; /** * Linux-specific policy configuration that is supported via the UI */ diff --git a/x-pack/plugins/security_solution/common/shared_exports.ts b/x-pack/plugins/security_solution/common/shared_exports.ts index 6269c3cee999c..bee2e54d0e3ea 100644 --- a/x-pack/plugins/security_solution/common/shared_exports.ts +++ b/x-pack/plugins/security_solution/common/shared_exports.ts @@ -16,3 +16,4 @@ export { exactCheck } from './exact_check'; export { getPaths, foldLeftRight } from './test_utils'; export { validate, validateEither } from './validate'; export { formatErrors } from './format_errors'; +export { migratePackagePolicyToV7110 } from './endpoint/policy/migrations/to_v7_11.0'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts index 0eedecef22170..b76e0c8acf4c3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts @@ -238,11 +238,23 @@ describe('policy details: ', () => { security: true, }, malware: { mode: 'prevent' }, + popup: { + malware: { + enabled: true, + message: '', + }, + }, logging: { file: 'info' }, }, mac: { events: { process: true, file: true, network: true }, malware: { mode: 'prevent' }, + popup: { + malware: { + enabled: true, + message: '', + }, + }, logging: { file: 'info' }, }, linux: { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts index c236b2841fc85..953438526b87e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts @@ -105,10 +105,12 @@ export const policyConfig: (s: PolicyDetailsState) => UIPolicyConfig = createSel windows: { events: windows.events, malware: windows.malware, + popup: windows.popup, }, mac: { events: mac.events, malware: mac.malware, + popup: mac.popup, }, linux: { events: linux.events, diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx index 1698f5bc3fd0c..1da832fb081ef 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx @@ -14,6 +14,7 @@ import { EuiSpacer, htmlIdGenerator, EuiCallOut, + EuiCheckbox, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -50,6 +51,11 @@ const ProtectionRadio = React.memo(({ id, label }: { id: ProtectionModes; label: const newPayload = clone(policyDetailsConfig); for (const os of OSes) { newPayload[os][protection].mode = id; + if (id === ProtectionModes.prevent) { + newPayload[os].popup[protection].enabled = true; + } else { + newPayload[os].popup[protection].enabled = false; + } } dispatch({ type: 'userChangedPolicyConfig', @@ -85,6 +91,8 @@ export const MalwareProtections = React.memo(() => { const dispatch = useDispatch(); // currently just taking windows.malware, but both windows.malware and mac.malware should be the same value const selected = policyDetailsConfig && policyDetailsConfig.windows.malware.mode; + const userNotificationSelected = + policyDetailsConfig && policyDetailsConfig.windows.popup.malware.enabled; const radios: Immutable { if (event.target.checked === false) { for (const os of OSes) { newPayload[os][protection].mode = ProtectionModes.off; + newPayload[os].popup[protection].enabled = event.target.checked; } } else { for (const os of OSes) { newPayload[os][protection].mode = ProtectionModes.prevent; + newPayload[os].popup[protection].enabled = event.target.checked; } } dispatch({ @@ -131,6 +141,22 @@ export const MalwareProtections = React.memo(() => { [dispatch, policyDetailsConfig] ); + const handleUserNotificationCheckbox = useCallback( + (event) => { + if (policyDetailsConfig) { + const newPayload = clone(policyDetailsConfig); + for (const os of OSes) { + newPayload[os].popup[protection].enabled = event.target.checked; + } + dispatch({ + type: 'userChangedPolicyConfig', + payload: { policyConfig: newPayload }, + }); + } + }, + [policyDetailsConfig, dispatch] + ); + const radioButtons = useMemo(() => { return ( <> @@ -154,9 +180,27 @@ export const MalwareProtections = React.memo(() => { ); })} + + +
+ +
+
+ ); - }, [radios]); + }, [radios, handleUserNotificationCheckbox, userNotificationSelected]); const protectionSwitch = useMemo(() => { return ( diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index e3cb7cd294f46..1f6973ae0f988 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -206,6 +206,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { events: { file: false, network: true, process: true }, logging: { file: 'info' }, malware: { mode: 'prevent' }, + popup: { + malware: { + enabled: true, + message: '', + }, + }, }, windows: { events: { @@ -219,6 +225,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }, logging: { file: 'info' }, malware: { mode: 'prevent' }, + popup: { + malware: { + enabled: true, + message: '', + }, + }, }, }, streams: [],