Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution] [Endpoint] Add blocklist tab in policy view #127458

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 @@ -15,6 +15,7 @@ export const MANAGEMENT_ROUTING_POLICY_DETAILS_FORM_PATH = `${MANAGEMENT_PATH}/:
export const MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/trustedApps`;
export const MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/eventFilters`;
export const MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/hostIsolationExceptions`;
export const MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/blocklists`;
/** @deprecated use the paths defined above instead */
export const MANAGEMENT_ROUTING_POLICY_DETAILS_PATH_OLD = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId`;
export const MANAGEMENT_ROUTING_TRUSTED_APPS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.trustedApps})`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { isEmpty } from 'lodash/fp';
import querystring from 'querystring';
import { generatePath } from 'react-router-dom';
import { appendSearch } from '../../common/components/link_to/helpers';
import { ArtifactListPageUrlParams } from '../components/artifact_list_page';
import { EndpointIndexUIQueryParams } from '../pages/endpoint_hosts/types';
import { EventFiltersPageLocation } from '../pages/event_filters/types';
import { HostIsolationExceptionsPageLocation } from '../pages/host_isolation_exceptions/types';
Expand All @@ -29,6 +30,8 @@ import {
MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH,
MANAGEMENT_ROUTING_TRUSTED_APPS_PATH,
MANAGEMENT_ROUTING_BLOCKLIST_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH,
} from './constants';

// Taken from: https://github.com/microsoft/TypeScript/issues/12936#issuecomment-559034150
Expand Down Expand Up @@ -215,6 +218,29 @@ const normalizeEventFiltersPageLocation = (
}
};

const normalizBlocklistsPageLocation = (
location?: Partial<ArtifactListPageUrlParams>
): Partial<ArtifactListPageUrlParams> => {
if (location) {
return {
...(!isDefaultOrMissing(location.page, MANAGEMENT_DEFAULT_PAGE)
? { page: location.page }
: {}),
...(!isDefaultOrMissing(location.pageSize, MANAGEMENT_DEFAULT_PAGE_SIZE)
? { pageSize: location.pageSize }
: {}),
...(!isDefaultOrMissing(location.show, undefined) ? { show: location.show } : {}),
...(!isDefaultOrMissing(location.itemId, undefined) ? { id: location.itemId } : {}),
...(!isDefaultOrMissing(location.filter, '') ? { filter: location.filter } : ''),
...(!isDefaultOrMissing(location.includedPolicies, '')
? { includedPolicies: location.includedPolicies }
: ''),
};
} else {
return {};
}
};

const normalizeHostIsolationExceptionsPageLocation = (
location?: Partial<HostIsolationExceptionsPageLocation>
): Partial<EventFiltersPageLocation> => {
Expand Down Expand Up @@ -407,3 +433,24 @@ export const getPolicyHostIsolationExceptionsPath = (
querystring.stringify(normalizePolicyDetailsArtifactsListPageLocation(location))
)}`;
};

export const getBlocklistsListPath = (location?: Partial<ArtifactListPageUrlParams>): string => {
const path = generatePath(MANAGEMENT_ROUTING_BLOCKLIST_PATH, {
tabName: AdministrationSubTab.blocklist,
});

return `${path}${appendSearch(querystring.stringify(normalizBlocklistsPageLocation(location)))}`;
};

export const getPolicyBlocklistsPath = (
policyId: string,
location?: Partial<PolicyDetailsArtifactsPageLocation>
) => {
const path = generatePath(MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, {
tabName: AdministrationSubTab.policies,
policyId,
});
return `${path}${appendSearch(
querystring.stringify(normalizePolicyDetailsArtifactsListPageLocation(location))
)}`;
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ export const BLOCKLISTS_LIST_DEFINITION: CreateExceptionListSchema = {
list_id: ENDPOINT_BLOCKLISTS_LIST_ID,
type: BLOCKLISTS_LIST_TYPE,
};

export const SEARCHABLE_FIELDS: Readonly<string[]> = [
`name`,
`description`,
'item_id',
`entries.value`,
`entries.entries.value`,
`comments.comment`,
];
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
MANAGEMENT_ROUTING_POLICY_DETAILS_PATH_OLD,
MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH,
MANAGEMENT_ROUTING_POLICIES_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH,
} from '../../common/constants';
import { NotFoundPage } from '../../../app/404';
import { getPolicyDetailPath } from '../../common/routing';
Expand All @@ -30,6 +31,7 @@ export const PolicyContainer = memo(() => {
MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH,
]}
exact
component={PolicyDetails}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH,
} from '../../../../../common/constants';
import { PolicyDetailsSelector, PolicyDetailsState } from '../../../types';

Expand Down Expand Up @@ -76,3 +77,16 @@ export const isOnHostIsolationExceptionsView: PolicyDetailsSelector<boolean> = c
);
}
);

/** Returns a boolean of whether the user is on the blocklists page or not */
export const isOnBlocklistsView: PolicyDetailsSelector<boolean> = createSelector(
getUrlLocationPathname,
(pathname) => {
return (
matchPath(pathname ?? '', {
path: MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH,
exact: true,
}) !== null
);
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH,
} from '../../../../../common/constants';
import { ManagementRoutePolicyDetailsParams } from '../../../../../types';
import { getPolicyDataForUpdate } from '../../../../../../../common/endpoint/service/policy';
Expand All @@ -31,6 +32,7 @@ import {
isOnPolicyEventFiltersView,
isOnHostIsolationExceptionsView,
isOnPolicyFormView,
isOnBlocklistsView,
} from './policy_common_selectors';

/** Returns the policy details */
Expand Down Expand Up @@ -93,7 +95,8 @@ export const isOnPolicyDetailsPage = (state: Immutable<PolicyDetailsState>) =>
isOnPolicyFormView(state) ||
isOnPolicyTrustedAppsView(state) ||
isOnPolicyEventFiltersView(state) ||
isOnHostIsolationExceptionsView(state);
isOnHostIsolationExceptionsView(state) ||
isOnBlocklistsView(state);

/** Returns the license info fetched from the license service */
export const license = (state: Immutable<PolicyDetailsState>) => {
Expand All @@ -111,6 +114,7 @@ export const policyIdFromParams: (state: Immutable<PolicyDetailsState>) => strin
MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH,
],
exact: true,
})?.params?.policyId ?? ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useCallback } from 'react';
import { useHistory } from 'react-router-dom';
import { useSelector } from 'react-redux';
import {
ENDPOINT_BLOCKLISTS_LIST_ID,
ENDPOINT_EVENT_FILTERS_LIST_ID,
ENDPOINT_TRUSTED_APPS_LIST_ID,
} from '@kbn/securitysolution-list-constants';
Expand All @@ -19,6 +20,7 @@ import {
MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE,
} from '../../../common/constants';
import {
getPolicyBlocklistsPath,
getPolicyDetailsArtifactsListPath,
getPolicyEventFiltersPath,
getPolicyHostIsolationExceptionsPath,
Expand Down Expand Up @@ -79,6 +81,11 @@ export function usePolicyDetailsArtifactsNavigateCallback(listId: string) {
...location,
...args,
});
} else if (listId === ENDPOINT_BLOCKLISTS_LIST_ID) {
return getPolicyBlocklistsPath(policyId, {
...location,
...args,
});
} else {
return getPolicyHostIsolationExceptionsPath(policyId, {
...location,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { i18n } from '@kbn/i18n';
import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';

export const POLICY_ARTIFACT_BLOCKLISTS_LABELS = Object.freeze({
deleteModalTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.list.removeDialog.title',
{
defaultMessage: 'Remove blocklist from policy',
}
),
deleteModalImpactInfo: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.list.removeDialog.messageCallout',
{
defaultMessage:
'This blocklist will be removed only from this policy and can still be found and managed from the artifact page.',
}
),
deleteModalErrorMessage: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.list.removeDialog.errorToastTitle',
{
defaultMessage: 'Error while attempting to remove blocklist',
}
),
flyoutWarningCalloutMessage: (maxNumber: number) =>
i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.searchWarning.text',
{
defaultMessage:
'Only the first {maxNumber} blocklists are displayed. Please use the search bar to refine the results.',
values: { maxNumber },
}
),
flyoutNoArtifactsToBeAssignedMessage: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.noAssignable',
{
defaultMessage: 'There are no blocklists that can be assigned to this policy.',
}
),
flyoutTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.title',
{
defaultMessage: 'Assign blocklists',
}
),
flyoutSubtitle: (policyName: string): string =>
i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.subtitle', {
defaultMessage: 'Select blocklists to add to {policyName}',
values: { policyName },
}),
flyoutSearchPlaceholder: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.search.label',
{
defaultMessage: 'Search blocklists',
}
),
flyoutErrorMessage: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.toastError.text',
{
defaultMessage: `An error occurred updating blocklists`,
}
),
flyoutSuccessMessageText: (updatedExceptions: ExceptionListItemSchema[]): string =>
updatedExceptions.length > 1
? i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.toastSuccess.textMultiples',
{
defaultMessage: '{count} blocklists have been added to your list.',
values: { count: updatedExceptions.length },
}
)
: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.toastSuccess.textSingle',
{
defaultMessage: '"{name}" has been added to your blocklist list.',
values: { name: updatedExceptions[0].name },
}
),
emptyUnassignedTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.title',
{ defaultMessage: 'No assigned blocklists' }
),
emptyUnassignedMessage: (policyName: string): string =>
i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.content', {
defaultMessage:
'There are currently no blocklists assigned to {policyName}. Assign blocklists now or add and manage them on the blocklists page.',
values: { policyName },
}),
emptyUnassignedPrimaryActionButtonTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.primaryAction',
{
defaultMessage: 'Assign blocklists',
}
),
emptyUnassignedSecondaryActionButtonTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.secondaryAction',
{
defaultMessage: 'Manage blocklists',
}
),
emptyUnexistingTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.empty.unexisting.title',
{ defaultMessage: 'No blocklists exist' }
),
emptyUnexistingMessage: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.empty.unexisting.content',
{
defaultMessage: 'There are currently no blocklists applied to your endpoints.',
}
),
emptyUnexistingPrimaryActionButtonTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.empty.unexisting.action',
{ defaultMessage: 'Add blocklists' }
),
listTotalItemCountMessage: (totalItemsCount: number): string =>
i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.list.totalItemCount', {
defaultMessage: 'Showing {totalItemsCount, plural, one {# blocklist} other {# blocklists}}',
values: { totalItemsCount },
}),
listRemoveActionNotAllowedMessage: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.list.removeActionNotAllowed',
{
defaultMessage: 'Globally applied blocklist cannot be removed from policy.',
}
),
listSearchPlaceholderMessage: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.list.search.placeholder',
{
defaultMessage: `Search on the fields below: name, description, IP`,
}
),
layoutTitle: i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.layout.title', {
defaultMessage: 'Assigned blocklists',
}),
layoutAssignButtonTitle: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.assignToPolicy',
{
defaultMessage: 'Assign blocklists to policy',
}
),
layoutViewAllLinkMessage: i18n.translate(
'xpack.securitySolution.endpoint.policy.blocklists.layout.about.viewAllLinkLabel',
{
defaultMessage: 'view all blocklists',
}
),
});
Loading