Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,16 @@ export enum ProductFeatureSecurityKey {
osqueryAutomatedResponseActions = 'osquery_automated_response_actions',

/**
* Enables Agent Tamper Protection
* Enables Protection Updates
*/
endpointProtectionUpdates = 'endpoint_protection_updates',

/**
* Enables Endpoint Custom Notification
*/

endpointCustomNotification = 'endpoint_custom_notification',

/**
* Enables Agent Tamper Protection
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export const securityDefaultProductFeaturesConfig: DefaultSecurityProductFeature
[ProductFeatureSecurityKey.osqueryAutomatedResponseActions]: {},
[ProductFeatureSecurityKey.endpointProtectionUpdates]: {},
[ProductFeatureSecurityKey.endpointAgentTamperProtection]: {},
[ProductFeatureSecurityKey.endpointCustomNotification]: {},
[ProductFeatureSecurityKey.externalRuleActions]: {},
[ProductFeatureSecurityKey.cloudSecurityPosture]: {},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type UpsellingSectionId =
| 'osquery_automated_response_actions'
| 'endpoint_protection_updates'
| 'endpoint_agent_tamper_protection'
| 'endpoint_custom_notification'
| 'cloud_security_posture_integration_installation'
| 'ruleDetailsEndpointExceptions'
| 'integration_assistant';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@

import type { PolicyConfig } from '../types';
import { PolicyOperatingSystem, ProtectionModes, AntivirusRegistrationModes } from '../types';
import { policyFactory } from './policy_config';
import { DefaultPolicyNotificationMessage, policyFactory } from './policy_config';
import {
disableProtections,
isPolicySetToEventCollectionOnly,
ensureOnlyEventCollectionIsAllowed,
isBillablePolicy,
getPolicyProtectionsReference,
checkIfPopupMessagesContainCustomNotifications,
resetCustomNotifications,
} from './policy_config_helpers';
import { set } from 'lodash';
import { get, merge, set } from 'lodash';

describe('Policy Config helpers', () => {
describe('disableProtections', () => {
Expand Down Expand Up @@ -223,6 +225,107 @@ describe('Policy Config helpers', () => {
}
);
});

describe('checkIfPopupMessagesContainCustomNotifications', () => {
let policy: PolicyConfig;

beforeEach(() => {
policy = policyFactory();
});

it('returns false when all popup messages are default', () => {
expect(checkIfPopupMessagesContainCustomNotifications(policy)).toBe(false);
});

it('returns true when any popup message is custom', () => {
set(policy, 'windows.popup.malware.message', 'Custom message');
expect(checkIfPopupMessagesContainCustomNotifications(policy)).toBe(true);
});

it('returns false when all popup messages are empty', () => {
set(policy, 'windows.popup.malware.message', '');
set(policy, 'mac.popup.memory_protection.message', '');
expect(checkIfPopupMessagesContainCustomNotifications(policy)).toBe(false);
});

it('returns true when any popup message is not empty or default', () => {
set(policy, 'linux.popup.behavior_protection.message', 'Another custom message');
expect(checkIfPopupMessagesContainCustomNotifications(policy)).toBe(true);
});

it('returns false when all popup messages are default across all OS', () => {
set(policy, 'windows.popup.malware.message', DefaultPolicyNotificationMessage);
set(policy, 'mac.popup.memory_protection.message', DefaultPolicyNotificationMessage);
set(policy, 'linux.popup.behavior_protection.message', DefaultPolicyNotificationMessage);
set(policy, 'windows.popup.ransomware.message', '');
expect(checkIfPopupMessagesContainCustomNotifications(policy)).toBe(false);
});
});

describe('resetCustomNotifications', () => {
let policy: PolicyConfig;

beforeEach(() => {
policy = policyFactory();
});

it.each([
'windows.popup.malware.message',
'windows.popup.behavior_protection.message',
'windows.popup.memory_protection.message',
'windows.popup.ransomware.message',
'linux.popup.malware.message',
'linux.popup.behavior_protection.message',
'linux.popup.memory_protection.message',
'mac.popup.malware.message',
'mac.popup.behavior_protection.message',
'mac.popup.memory_protection.message',
])('resets %s to default message', (keyPath) => {
set(policy, keyPath, `Custom message`);
const defaultNotifications = resetCustomNotifications();

const updatedPolicy = merge({}, policy, defaultNotifications);
expect(get(updatedPolicy, keyPath)).toBe(DefaultPolicyNotificationMessage);
});

it('does not change default messages', () => {
set(policy, 'windows.popup.malware.message', DefaultPolicyNotificationMessage);
const defaultNotifications = resetCustomNotifications();

const updatedPolicy = merge({}, policy, defaultNotifications);
expect(get(updatedPolicy, 'windows.popup.malware.message')).toBe(
DefaultPolicyNotificationMessage
);
});

it('resets empty messages to default messages', () => {
set(policy, 'windows.popup.malware.message', '');
const defaultNotifications = resetCustomNotifications();

const updatedPolicy = merge({}, policy, defaultNotifications);
expect(get(updatedPolicy, 'windows.popup.malware.message')).toBe(
DefaultPolicyNotificationMessage
);
});

it('resets messages for all operating systems', () => {
set(policy, 'windows.popup.malware.message', 'Custom message');
set(policy, 'mac.popup.memory_protection.message', 'Another custom message');
set(policy, 'linux.popup.behavior_protection.message', 'Yet another custom message');
const defaultNotifications = resetCustomNotifications();

const updatedPolicy = merge({}, policy, defaultNotifications);
expect(get(updatedPolicy, 'windows.popup.malware.message')).toBe(
DefaultPolicyNotificationMessage
);
expect(get(updatedPolicy, 'mac.popup.memory_protection.message')).toBe(
DefaultPolicyNotificationMessage
);
expect(get(updatedPolicy, 'linux.popup.behavior_protection.message')).toBe(
DefaultPolicyNotificationMessage
);
});
});
});

// This constant makes sure that if the type `PolicyConfig` is ever modified,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { get, set } from 'lodash';
import { DefaultPolicyNotificationMessage } from './policy_config';
import type { PolicyConfig } from '../types';
import { PolicyOperatingSystem, ProtectionModes, AntivirusRegistrationModes } from '../types';

Expand All @@ -22,6 +23,28 @@ const allOsValues = [
PolicyOperatingSystem.windows,
];

const getPolicyPopupReference = (): Array<{
keyPath: string;
osList: PolicyOperatingSystem[];
}> => [
{
keyPath: 'popup.malware.message',
osList: [...allOsValues],
},
{
keyPath: 'popup.memory_protection.message',
osList: [...allOsValues],
},
{
keyPath: 'popup.behavior_protection.message',
osList: [...allOsValues],
},
{
keyPath: 'popup.ransomware.message',
osList: [PolicyOperatingSystem.windows],
},
];

export const getPolicyProtectionsReference = (): PolicyProtectionReference[] => [
{
keyPath: 'malware.mode',
Expand Down Expand Up @@ -210,3 +233,28 @@ export function isBillablePolicy(policy: PolicyConfig) {

return !isPolicySetToEventCollectionOnly(policy).isOnlyCollectingEvents;
}

export const checkIfPopupMessagesContainCustomNotifications = (policy: PolicyConfig): boolean => {
const popupRefs = getPolicyPopupReference();

return popupRefs.some(({ keyPath, osList }) => {
return osList.some((osValue) => {
const fullKeyPathForOs = `${osValue}.${keyPath}`;
const currentValue = get(policy, fullKeyPathForOs);
return currentValue !== '' && currentValue !== DefaultPolicyNotificationMessage;
});
});
};

export const resetCustomNotifications = (
customNotification = DefaultPolicyNotificationMessage
): Partial<PolicyConfig> => {
const popupRefs = getPolicyPopupReference();

return popupRefs.reduce((acc, { keyPath, osList }) => {
osList.forEach((osValue) => {
set(acc, `${osValue}.${keyPath}`, customNotification);
});
return acc;
}, {});
};
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe(
login();
});

it('should display upselling section for protection updates', () => {
it('should not display upselling section for protection updates', () => {
loadPage(`${APP_POLICIES_PATH}/${policyId}/protectionUpdates`);
[
'endpointPolicy-protectionUpdatesLockedCard-title',
Expand All @@ -67,5 +67,29 @@ describe(
cy.getByTestSubj(testSubj).should('exist').and('be.visible');
});
});

it(`should not display upselling section for custom notification`, () => {
const testData = ['malware', 'ransomware', 'memory', 'behaviour'];

loadPage(`${APP_POLICIES_PATH}/${policyId}/settings`);

testData.forEach((protection) => {
cy.getByTestSubj(`endpointPolicyForm-${protection}`).within(() => {
cy.getByTestSubj(`endpointPolicyForm-${protection}-enableDisableSwitch`).click();
// User should not see the locked card since the feature is available under Endpoint Complete tier
[
'endpointPolicy-customNotificationLockedCard-title',
'endpointPolicy-customNotificationLockedCard',
'endpointPolicy-customNotificationLockedCard-badge',
].forEach((testSubj) => {
cy.getByTestSubj(testSubj).should('not.exist');
});
// User should see the custom notification section
cy.getByTestSubj(`endpointPolicyForm-${protection}-notifyUser-customMessage`)
.should('exist')
.and('be.visible');
});
});
});
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,29 @@ describe(
});
cy.getByTestSubj('protection-updates-layout').should('not.exist');
});

it(`should display upselling section for custom notification`, () => {
const testData = ['malware', 'ransomware', 'memory', 'behaviour'];

loadPage(`${APP_POLICIES_PATH}/${policyId}/settings`);

testData.forEach((protection) => {
cy.getByTestSubj(`endpointPolicyForm-${protection}`).within(() => {
cy.getByTestSubj(`endpointPolicyForm-${protection}-enableDisableSwitch`).click();
// User should see the custom notification locked card since it is not enabled under Endpoint Essentials
[
'endpointPolicy-customNotificationLockedCard-title',
'endpointPolicy-customNotificationLockedCard',
'endpointPolicy-customNotificationLockedCard-badge',
].forEach((testSubj) => {
cy.getByTestSubj(testSubj, { timeout: 60000 }).should('exist').and('be.visible');
});
// User should not see the custom message input since it is not enabled under Endpoint Essentials
cy.getByTestSubj(`endpointPolicyForm-${protection}-notifyUser-customMessage`).should(
'not.exist'
);
});
});
});
}
);
Loading