From a9d921030043a23784333234ef2cb8b9104fa63c Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 15:37:29 -0400 Subject: [PATCH 01/16] allow unknown experimental features to be defined and log them as unused --- .../common/experimental_features.ts | 25 ++++++++------- .../public/common/store/reducer.test.ts | 2 +- .../security_solution/public/plugin.tsx | 4 ++- .../security_solution/server/config.mock.ts | 4 +-- .../security_solution/server/config.ts | 32 +++++++++---------- .../server/endpoint/mocks.ts | 2 +- .../manifest_manager/manifest_manager.mock.ts | 2 +- 7 files changed, 36 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 0e44190bfab78..1c94f4248a61a 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -148,7 +148,6 @@ export const allowedExperimentalValues = Object.freeze({ type ExperimentalConfigKeys = Array; type Mutable = { -readonly [P in keyof T]: T[P] }; -const SecuritySolutionInvalidExperimentalValue = class extends Error {}; const allowedKeys = Object.keys(allowedExperimentalValues) as Readonly; /** @@ -158,25 +157,27 @@ const allowedKeys = Object.keys(allowedExperimentalValues) as Readonly { +export const parseExperimentalConfigValue = ( + configValue: string[] +): { features: ExperimentalFeatures; invalid: string[] } => { const enabledFeatures: Mutable> = {}; + const invalidKeys: string[] = []; for (const value of configValue) { - if (!isValidExperimentalValue(value)) { - throw new SecuritySolutionInvalidExperimentalValue(`[${value}] is not valid.`); + if (!allowedKeys.includes(value as keyof ExperimentalFeatures)) { + invalidKeys.push(value); + } else { + enabledFeatures[value as keyof ExperimentalFeatures] = true; } - - enabledFeatures[value as keyof ExperimentalFeatures] = true; } return { - ...allowedExperimentalValues, - ...enabledFeatures, + features: { + ...allowedExperimentalValues, + ...enabledFeatures, + }, + invalid: invalidKeys, }; }; -export const isValidExperimentalValue = (value: string): value is keyof ExperimentalFeatures => { - return allowedKeys.includes(value as keyof ExperimentalFeatures); -}; - export const getExperimentalAllowedValues = (): string[] => [...allowedKeys]; diff --git a/x-pack/plugins/security_solution/public/common/store/reducer.test.ts b/x-pack/plugins/security_solution/public/common/store/reducer.test.ts index 35a30738eb6f1..705902596fbbf 100644 --- a/x-pack/plugins/security_solution/public/common/store/reducer.test.ts +++ b/x-pack/plugins/security_solution/public/common/store/reducer.test.ts @@ -35,7 +35,7 @@ describe('createInitialState', () => { >; const defaultState = { defaultDataView: mockSourcererState.defaultDataView, - enableExperimental: parseExperimentalConfigValue([]), + enableExperimental: parseExperimentalConfigValue([]).features, kibanaDataViews: [mockSourcererState.defaultDataView], signalIndexName: 'siem-signals-default', }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index b13a200161d22..f506a0a04d3f1 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -86,7 +86,9 @@ export class Plugin implements IPlugin(); - this.experimentalFeatures = parseExperimentalConfigValue(this.config.enableExperimental || []); + this.experimentalFeatures = parseExperimentalConfigValue( + this.config.enableExperimental || [] + ).features; this.kibanaVersion = initializerContext.env.packageInfo.version; this.kibanaBranch = initializerContext.env.packageInfo.branch; this.prebuiltRulesPackageVersion = this.config.prebuiltRulesPackageVersion; diff --git a/x-pack/plugins/security_solution/server/config.mock.ts b/x-pack/plugins/security_solution/server/config.mock.ts index b0d06b40a2b84..ca655d103e279 100644 --- a/x-pack/plugins/security_solution/server/config.mock.ts +++ b/x-pack/plugins/security_solution/server/config.mock.ts @@ -32,7 +32,7 @@ export const createMockConfig = (): ConfigType => { alertIgnoreFields: [], maxUploadResponseActionFileBytes: 26214400, - experimentalFeatures: parseExperimentalConfigValue(enableExperimental), + experimentalFeatures: parseExperimentalConfigValue(enableExperimental).features, enabled: true, }; }; @@ -45,7 +45,7 @@ const withExperimentalFeature = ( return { ...config, enableExperimental, - experimentalFeatures: parseExperimentalConfigValue(enableExperimental), + experimentalFeatures: parseExperimentalConfigValue(enableExperimental).features, }; }; diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts index 44ff0e4d1aa73..dc732061ab947 100644 --- a/x-pack/plugins/security_solution/server/config.ts +++ b/x-pack/plugins/security_solution/server/config.ts @@ -10,13 +10,7 @@ import { schema } from '@kbn/config-schema'; import type { PluginInitializerContext } from '@kbn/core/server'; import { SIGNALS_INDEX_KEY, DEFAULT_SIGNALS_INDEX } from '../common/constants'; import type { ExperimentalFeatures } from '../common/experimental_features'; -import { - getExperimentalAllowedValues, - isValidExperimentalValue, - parseExperimentalConfigValue, -} from '../common/experimental_features'; - -const allowedExperimentalValues = getExperimentalAllowedValues(); +import { parseExperimentalConfigValue } from '../common/experimental_features'; export const configSchema = schema.object({ maxRuleImportExportSize: schema.number({ defaultValue: 10000 }), @@ -94,15 +88,6 @@ export const configSchema = schema.object({ */ enableExperimental: schema.arrayOf(schema.string(), { defaultValue: () => [], - validate(list) { - for (const key of list) { - if (!isValidExperimentalValue(key)) { - return `[${key}] is not allowed. Allowed values are: ${allowedExperimentalValues.join( - ', ' - )}`; - } - } - }, }), /** @@ -141,7 +126,20 @@ export type ConfigType = ConfigSchema & { export const createConfig = (context: PluginInitializerContext): ConfigType => { const pluginConfig = context.config.get>(); - const experimentalFeatures = parseExperimentalConfigValue(pluginConfig.enableExperimental); + const logger = context.logger.get('config'); + + const { invalid, features: experimentalFeatures } = parseExperimentalConfigValue( + pluginConfig.enableExperimental + ); + + if (invalid.length) { + logger.warn(`Unsupported "xpack.securitySolution.enableExperimental" values detected. +The following configuration values are no longer supported and should be removed from the kibana configuration file: + + xpack.securitySolution.enableExperimental: +${invalid.map((key) => ` - ${key}`).join('\n')} +`); + } return { ...pluginConfig, diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 959ac0bf51ef3..b2e1202790b9b 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -83,7 +83,7 @@ export const createMockEndpointAppContext = ( config: () => Promise.resolve(config), serverConfig: config, service: createMockEndpointAppContextService(mockManifestManager), - experimentalFeatures: parseExperimentalConfigValue(config.enableExperimental), + experimentalFeatures: parseExperimentalConfigValue(config.enableExperimental).features, }; }; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts index 10eccac516847..dda2d60ca94e3 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts @@ -90,7 +90,7 @@ export const buildManifestManagerContextMock = ( ...fullOpts, artifactClient: createEndpointArtifactClientMock(), logger: loggingSystemMock.create().get() as jest.Mocked, - experimentalFeatures: parseExperimentalConfigValue([]), + experimentalFeatures: parseExperimentalConfigValue([]).features, }; }; From b30819a6ae9a9b29653f10c43de516c0b7c7c15b Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 15:43:24 -0400 Subject: [PATCH 02/16] Remove `policyListEnabled` feature flag --- .../common/experimental_features.ts | 1 - .../public/management/links.ts | 1 - .../public/management/pages/policy/index.tsx | 6 +-- .../pages/policy/view/policy_details.test.tsx | 6 --- .../pages/policy/view/policy_details.tsx | 50 ++++++------------- .../components/policy_form_layout.tsx | 10 ++-- 6 files changed, 19 insertions(+), 55 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 1c94f4248a61a..92a8ecde88194 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -18,7 +18,6 @@ export const allowedExperimentalValues = Object.freeze({ kubernetesEnabled: true, disableIsolationUIPendingStatuses: false, pendingActionResponsesWithAck: true, - policyListEnabled: true, policyResponseInFleetEnabled: true, chartEmbeddablesEnabled: true, donutChartEmbeddablesEnabled: false, // Depends on https://github.com/elastic/kibana/issues/136409 item 2 - 6 diff --git a/x-pack/plugins/security_solution/public/management/links.ts b/x-pack/plugins/security_solution/public/management/links.ts index 81b2c9e35af96..07a559f92927f 100644 --- a/x-pack/plugins/security_solution/public/management/links.ts +++ b/x-pack/plugins/security_solution/public/management/links.ts @@ -165,7 +165,6 @@ export const links: LinkItem = { path: POLICIES_PATH, skipUrlState: true, hideTimeline: true, - experimentalKey: 'policyListEnabled', }, { id: SecurityPageName.trustedApps, diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx index 50556686438ae..e9eef8c5a8132 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx @@ -21,10 +21,8 @@ import { } from '../../common/constants'; import { NotFoundPage } from '../../../app/404'; import { getPolicyDetailPath } from '../../common/routing'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; export const PolicyContainer = memo(() => { - const isPolicyListEnabled = useIsExperimentalFeatureEnabled('policyListEnabled'); return ( { exact render={(props) => } /> - {isPolicyListEnabled && ( - - )} + ); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx index 3505f242b8ca9..020ef18ed0d8b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx @@ -27,16 +27,13 @@ import { import { policyListApiPathHandlers } from '../store/test_mock_utils'; import { PolicyDetails } from './policy_details'; import { APP_UI_ID } from '../../../../../common/constants'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; jest.mock('./policy_forms/components/policy_form_layout', () => ({ PolicyFormLayout: () => <>, })); jest.mock('../../../../common/components/user_privileges'); -jest.mock('../../../../common/hooks/use_experimental_features'); const useUserPrivilegesMock = useUserPrivileges as jest.Mock; -const useIsExperimentalFeatureMock = useIsExperimentalFeatureEnabled as jest.Mock; describe('Policy Details', () => { const policyDetailsPathUrl = getPolicyDetailPath('1'); @@ -66,9 +63,6 @@ describe('Policy Details', () => { let releaseApiFailure: () => void; beforeEach(() => { - useIsExperimentalFeatureMock.mockReturnValue({ - policyListEnabled: true, - }); http.get.mockImplementation(async () => { await new Promise((_, reject) => { releaseApiFailure = reject.bind(null, new Error('policy not found')); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx index c02937b15d56d..04d9e14efa5b9 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx @@ -21,13 +21,11 @@ import { AdministrationListPage } from '../../../components/administration_list_ import type { BackToExternalAppButtonProps } from '../../../components/back_to_external_app_button/back_to_external_app_button'; import { BackToExternalAppButton } from '../../../components/back_to_external_app_button/back_to_external_app_button'; import type { PolicyDetailsRouteState } from '../../../../../common/endpoint/types'; -import { getEndpointListPath, getPoliciesPath } from '../../../common/routing'; +import { getPoliciesPath } from '../../../common/routing'; import { useAppUrl } from '../../../../common/lib/kibana'; import { APP_UI_ID } from '../../../../../common/constants'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; export const PolicyDetails = React.memo(() => { - const isPolicyListEnabled = useIsExperimentalFeatureEnabled('policyListEnabled'); const { state: routeState = {} } = useLocation(); const { getAppUrl } = useAppUrl(); @@ -49,38 +47,20 @@ export const PolicyDetails = React.memo(() => { }; } - if (isPolicyListEnabled) { - // default is to go back to the policy list - const policyListPath = getPoliciesPath(); - return { - backButtonLabel: i18n.translate('xpack.securitySolution.policyDetails.backToPolicyButton', { - defaultMessage: 'Back to policy list', - }), - backButtonUrl: getAppUrl({ path: policyListPath }), - onBackButtonNavigateTo: [ - APP_UI_ID, - { - path: policyListPath, - }, - ], - }; - } else { - // remove else block once policy list is not hidden behind feature flag - const endpointListPath = getEndpointListPath({ name: 'endpointList' }); - return { - backButtonLabel: i18n.translate('xpack.securitySolution.policyDetails.backToEndpointList', { - defaultMessage: 'View all endpoints', - }), - backButtonUrl: getAppUrl({ path: endpointListPath }), - onBackButtonNavigateTo: [ - APP_UI_ID, - { - path: endpointListPath, - }, - ], - }; - } - }, [getAppUrl, routeState?.backLink, isPolicyListEnabled]); + const policyListPath = getPoliciesPath(); + return { + backButtonLabel: i18n.translate('xpack.securitySolution.policyDetails.backToPolicyButton', { + defaultMessage: 'Back to policy list', + }), + backButtonUrl: getAppUrl({ path: policyListPath }), + onBackButtonNavigateTo: [ + APP_UI_ID, + { + path: policyListPath, + }, + ], + }; + }, [getAppUrl, routeState.backLink]); const headerRightContent = ( { const [showConfirm, setShowConfirm] = useState(false); const [routeState, setRouteState] = useState(); const policyName = policyItem?.name ?? ''; - const isPolicyListEnabled = useIsExperimentalFeatureEnabled('policyListEnabled'); const routingOnCancelNavigateTo = routeState?.onCancelNavigateTo; const navigateToAppArguments = useMemo((): Parameters => { @@ -73,12 +71,10 @@ export const PolicyFormLayout = React.memo(() => { return [ APP_UI_ID, { - path: isPolicyListEnabled - ? getPoliciesPath() - : getEndpointListPath({ name: 'endpointList' }), + path: getPoliciesPath(), }, ]; - }, [isPolicyListEnabled, routingOnCancelNavigateTo]); + }, [routingOnCancelNavigateTo]); // Handle showing update statuses useEffect(() => { From 852cc57a0d730277c5a7b880d4b85e2f99c38d28 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 15:51:06 -0400 Subject: [PATCH 03/16] remove `disableIsolationUIPendingStatues` feature flag --- .../common/experimental_features.ts | 1 - .../endpoint_agent_status/endpoint_agent_status.tsx | 13 ------------- 2 files changed, 14 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 92a8ecde88194..9e722392c3720 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -16,7 +16,6 @@ export const allowedExperimentalValues = Object.freeze({ tGridEventRenderedViewEnabled: true, excludePoliciesInFilterEnabled: false, kubernetesEnabled: true, - disableIsolationUIPendingStatuses: false, pendingActionResponsesWithAck: true, policyResponseInFleetEnabled: true, chartEmbeddablesEnabled: true, diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/endpoint_agent_status/endpoint_agent_status.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/endpoint_agent_status/endpoint_agent_status.tsx index 1b2d021634a2f..47bd5ab94e291 100644 --- a/x-pack/plugins/security_solution/public/common/components/endpoint/endpoint_agent_status/endpoint_agent_status.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/endpoint_agent_status/endpoint_agent_status.tsx @@ -22,7 +22,6 @@ import { HOST_STATUS_TO_BADGE_COLOR } from '../../../../management/pages/endpoin import { getEmptyValue } from '../../empty_value'; import type { ResponseActionsApiCommandNames } from '../../../../../common/endpoint/service/response_actions/constants'; import { RESPONSE_ACTION_API_COMMANDS_TO_CONSOLE_COMMAND_MAP } from '../../../../../common/endpoint/service/response_actions/constants'; -import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; import { useGetEndpointPendingActionsSummary } from '../../../../management/hooks/response_actions/use_get_endpoint_pending_actions_summary'; import { useTestIdGenerator } from '../../../../management/hooks/use_test_id_generator'; import type { HostInfo, EndpointPendingActions } from '../../../../../common/endpoint/types'; @@ -187,9 +186,6 @@ interface EndpointHostResponseActionsStatusProps { const EndpointHostResponseActionsStatus = memo( ({ pendingActions, isIsolated, 'data-test-subj': dataTestSubj }) => { const getTestId = useTestIdGenerator(dataTestSubj); - const isPendingStatusDisabled = useIsExperimentalFeatureEnabled( - 'disableIsolationUIPendingStatuses' - ); interface PendingActionsState { actionList: Array<{ label: string; count: number }>; @@ -269,15 +265,6 @@ const EndpointHostResponseActionsStatus = memo Date: Fri, 2 Jun 2023 15:58:38 -0400 Subject: [PATCH 04/16] remove `responseActionsConsoleEnabled` feature flag --- .../common/experimental_features.ts | 5 ----- .../use_responder_action_item.tsx | 16 ++------------ .../take_action_dropdown/index.test.tsx | 22 ------------------- .../view/hooks/use_endpoint_action_items.tsx | 7 +----- 4 files changed, 3 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 9e722392c3720..6a78469ee1eef 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -31,11 +31,6 @@ export const allowedExperimentalValues = Object.freeze({ */ previewTelemetryUrlEnabled: false, - /** - * Enables the Endpoint response actions console in various areas of the app - */ - responseActionsConsoleEnabled: true, - /** * Enables the insights module for related alerts by process ancestry */ diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx index 8104e9a1703fc..9a9d8e7d7470d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx @@ -13,16 +13,12 @@ import { isTimelineEventItemAnAlert, } from '../../../common/utils/endpoint_alert_check'; import { ResponderContextMenuItem } from './responder_context_menu_item'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { getFieldValue } from '../host_isolation/helpers'; export const useResponderActionItem = ( eventDetailsData: TimelineEventsDetailsItem[] | null, onClick: () => void ): JSX.Element[] => { - const isResponseActionsConsoleEnabled = useIsExperimentalFeatureEnabled( - 'responseActionsConsoleEnabled' - ); const { loading: isAuthzLoading, canAccessResponseConsole } = useUserPrivileges().endpointPrivileges; @@ -42,7 +38,7 @@ export const useResponderActionItem = ( return useMemo(() => { const actions: JSX.Element[] = []; - if (isResponseActionsConsoleEnabled && !isAuthzLoading && canAccessResponseConsole && isAlert) { + if (!isAuthzLoading && canAccessResponseConsole && isAlert) { actions.push( { apiMocks = endpointMetadataHttpMocks(mockStartServicesMock.http as jest.Mocked); }); - describe('when the `responseActionsConsoleEnabled` feature flag is false', () => { - beforeAll(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((featureKey) => { - if (featureKey === 'responseActionsConsoleEnabled') { - return false; - } - return true; - }); - }); - - afterAll(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation(() => true); - }); - - it('should hide the button if feature flag if off', async () => { - render(); - - expect(findLaunchResponderButton()).toHaveLength(0); - }); - }); - it('should not display the button if user is not allowed to write event filters', async () => { (useUserPrivileges as jest.Mock).mockReturnValue({ ...mockInitialUserPrivilegesState(), diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx index 0a6c82ff452a2..eba863b3b8ddb 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx @@ -10,7 +10,6 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { pagePathGetters } from '@kbn/fleet-plugin/public'; import { useUserPrivileges } from '../../../../../common/components/user_privileges'; import { useWithShowEndpointResponder } from '../../../../hooks'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { APP_UI_ID } from '../../../../../../common/constants'; import { getEndpointDetailsPath, getEndpointListPath } from '../../../../common/routing'; import type { HostMetadata, MaybeImmutable } from '../../../../../../common/endpoint/types'; @@ -37,9 +36,6 @@ export const useEndpointActionItems = ( const fleetAgentPolicies = useEndpointSelector(agentPolicies); const allCurrentUrlParams = useEndpointSelector(uiQueryParams); const showEndpointResponseActionsConsole = useWithShowEndpointResponder(); - const isResponseActionsConsoleEnabled = useIsExperimentalFeatureEnabled( - 'responseActionsConsoleEnabled' - ); const { canAccessResponseConsole, canIsolateHost, @@ -123,7 +119,7 @@ export const useEndpointActionItems = ( return [ ...isolationActions, - ...(isResponseActionsConsoleEnabled && canAccessResponseConsole + ...(canAccessResponseConsole ? [ { 'data-test-subj': 'console', @@ -268,7 +264,6 @@ export const useEndpointActionItems = ( endpointMetadata, fleetAgentPolicies, getAppUrl, - isResponseActionsConsoleEnabled, showEndpointResponseActionsConsole, options?.isEndpointList, canIsolateHost, From c27b855bf2ee3c084be586e2cb81c62ec79b7f02 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 16:24:08 -0400 Subject: [PATCH 05/16] remove `endpointRbacEnabled` feature flag --- .../common/experimental_features.ts | 5 - .../endpoint/use_endpoint_privileges.test.ts | 3 - .../endpoint/use_endpoint_privileges.ts | 8 +- .../privileged_route.test.tsx | 108 +++++------------- .../privileged_route/privileged_route.tsx | 29 ++--- .../public/management/links.test.ts | 32 +----- .../public/management/links.ts | 11 +- .../pages/integration_tests/index.test.tsx | 22 ---- .../endpoint/endpoint_app_context_services.ts | 3 +- .../app_features/security_kibana_features.ts | 30 ++--- .../config.ts | 1 - 11 files changed, 53 insertions(+), 199 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 6a78469ee1eef..fcb1c650e6290 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -66,11 +66,6 @@ export const allowedExperimentalValues = Object.freeze({ */ endpointResponseActionsEnabled: false, - /** - * Enables endpoint package level rbac - */ - endpointRbacEnabled: true, - /** * Enables endpoint package level rbac for response actions only. * if endpointRbacEnabled is enabled, it will take precedence. diff --git a/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.test.ts b/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.test.ts index 89ce757f19d8b..d79df35bcfe2c 100644 --- a/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.test.ts @@ -36,9 +36,6 @@ jest.mock('../../../hooks/use_license', () => { }, }; }); -jest.mock('../../../hooks/use_experimental_features', () => ({ - useIsExperimentalFeatureEnabled: jest.fn((feature: string) => feature === 'endpointRbacEnabled'), -})); const useKibanaMock = useKibana as jest.Mocked; const useHttpMock = _useHttp as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts b/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts index 0e56d214fcb25..5fa2400dab6b9 100644 --- a/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts +++ b/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts @@ -22,7 +22,6 @@ import { getEndpointAuthzInitialState, } from '../../../../../common/endpoint/service/authz'; import { useSecuritySolutionStartDependencies } from './security_solution_start_dependencies'; -import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; /** * Retrieve the endpoint privileges for the current user. @@ -49,9 +48,6 @@ export const useEndpointPrivileges = (): Immutable => { const [userRolesCheckDone, setUserRolesCheckDone] = useState(false); const [userRoles, setUserRoles] = useState>([]); - const isEndpointRbacEnabled = useIsExperimentalFeatureEnabled('endpointRbacEnabled'); - const isEndpointRbacV1Enabled = useIsExperimentalFeatureEnabled('endpointRbacV1Enabled'); - const [checkHostIsolationExceptionsDone, setCheckHostIsolationExceptionsDone] = useState(false); const [hasHostIsolationExceptionsItems, setHasHostIsolationExceptionsItems] = @@ -67,7 +63,7 @@ export const useEndpointPrivileges = (): Immutable => { licenseService, fleetAuthz, userRoles, - isEndpointRbacEnabled || isEndpointRbacV1Enabled, + true, hasHostIsolationExceptionsItems ) : getEndpointAuthzInitialState()), @@ -81,8 +77,6 @@ export const useEndpointPrivileges = (): Immutable => { fleetAuthz, licenseService, userRoles, - isEndpointRbacEnabled, - isEndpointRbacV1Enabled, hasHostIsolationExceptionsItems, ]); diff --git a/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.test.tsx b/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.test.tsx index 2e4429bc1fd70..2fdac844b5e41 100644 --- a/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.test.tsx @@ -11,19 +11,15 @@ import type { AppContextTestRender } from '../../../common/mock/endpoint'; import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; import { PrivilegedRoute } from './privileged_route'; import type { PrivilegedRouteProps } from './privileged_route'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { AdministrationSubTab } from '../../types'; import { MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH } from '../../common/constants'; import { MANAGEMENT_PATH } from '../../../../common/constants'; -jest.mock('../../../common/hooks/use_experimental_features'); - describe('PrivilegedRoute', () => { const noPrivilegesPageTestId = 'noPrivilegesPage'; const noPermissionsPageTestId = 'noIngestPermissions'; const componentTestId = 'component-to-render'; - let featureFlags: { endpointRbacEnabled: boolean; endpointRbacV1Enabled: boolean }; let currentPath: string; let renderProps: PrivilegedRouteProps; @@ -31,7 +27,6 @@ describe('PrivilegedRoute', () => { let render: () => void; beforeEach(() => { - featureFlags = { endpointRbacEnabled: false, endpointRbacV1Enabled: false }; currentPath = 'path'; renderProps = { component: () =>
, @@ -50,96 +45,45 @@ describe('PrivilegedRoute', () => { ); }; - - const useIsExperimentalFeatureEnabledMock = (feature: keyof typeof featureFlags) => - featureFlags[feature]; - - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( - useIsExperimentalFeatureEnabledMock - ); }); - const testCommonPathsForAllFeatureFlags = () => { - it('renders component if it has privileges and on correct path', async () => { - render(); - - expect(renderResult.getByTestId(componentTestId)).toBeTruthy(); - expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); - expect(renderResult.queryByTestId(noPrivilegesPageTestId)).toBeNull(); - }); - - it('renders nothing if path is different', async () => { - renderProps.path = 'different'; - - render(); - - expect(renderResult.queryByTestId(componentTestId)).toBeNull(); - expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); - expect(renderResult.queryByTestId(noPrivilegesPageTestId)).toBeNull(); - }); - }; - - describe('no feature flags', () => { - testCommonPathsForAllFeatureFlags(); + it('renders component if it has privileges and on correct path', async () => { + render(); - it('renders `you need to be superuser` if no privileges', async () => { - renderProps.hasPrivilege = false; - - render(); - - expect(renderResult.getByTestId(noPermissionsPageTestId)).toBeTruthy(); - expect(renderResult.queryByTestId(componentTestId)).toBeNull(); - expect(renderResult.queryByTestId(noPrivilegesPageTestId)).toBeNull(); - }); + expect(renderResult.getByTestId(componentTestId)).toBeTruthy(); + expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); + expect(renderResult.queryByTestId(noPrivilegesPageTestId)).toBeNull(); }); - describe('endpointRbacV1Enabled', () => { - beforeEach(() => { - featureFlags.endpointRbacV1Enabled = true; - }); - - testCommonPathsForAllFeatureFlags(); - - describe('no privileges', () => { - it('renders `you need to have privileges` on Response actions history', async () => { - renderProps.hasPrivilege = false; - renderProps.path = MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH; - currentPath = `${MANAGEMENT_PATH}/${AdministrationSubTab.responseActionsHistory}`; + it('renders nothing if path is different', async () => { + renderProps.path = 'different'; - render(); + render(); - expect(renderResult.getByTestId(noPrivilegesPageTestId)).toBeTruthy(); - expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); - expect(renderResult.queryByTestId(componentTestId)).toBeNull(); - }); + expect(renderResult.queryByTestId(componentTestId)).toBeNull(); + expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); + expect(renderResult.queryByTestId(noPrivilegesPageTestId)).toBeNull(); + }); - it('renders `you need to be superuser` on other pages', async () => { - renderProps.hasPrivilege = false; + it('renders `you need to have privileges` on Response actions history', async () => { + renderProps.hasPrivilege = false; + renderProps.path = MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH; + currentPath = `${MANAGEMENT_PATH}/${AdministrationSubTab.responseActionsHistory}`; - render(); + render(); - expect(renderResult.getByTestId(noPermissionsPageTestId)).toBeTruthy(); - expect(renderResult.queryByTestId(noPrivilegesPageTestId)).toBeNull(); - expect(renderResult.queryByTestId(componentTestId)).toBeNull(); - }); - }); + expect(renderResult.getByTestId(noPrivilegesPageTestId)).toBeTruthy(); + expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); + expect(renderResult.queryByTestId(componentTestId)).toBeNull(); }); - describe('endpointRbacEnabled', () => { - beforeEach(() => { - featureFlags.endpointRbacEnabled = true; - }); - - testCommonPathsForAllFeatureFlags(); - - it('renders `you need to have RBAC privileges` if no privileges', async () => { - renderProps.hasPrivilege = false; + it('renders `you need to have RBAC privileges` if no privileges', async () => { + renderProps.hasPrivilege = false; - render(); + render(); - expect(renderResult.getByTestId(noPrivilegesPageTestId)).toBeTruthy(); - expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); - expect(renderResult.queryByTestId(componentTestId)).toBeNull(); - }); + expect(renderResult.getByTestId(noPrivilegesPageTestId)).toBeTruthy(); + expect(renderResult.queryByTestId(noPermissionsPageTestId)).toBeNull(); + expect(renderResult.queryByTestId(componentTestId)).toBeNull(); }); }); diff --git a/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx b/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx index 3ec48101f6a02..0493aadd67211 100644 --- a/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx +++ b/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx @@ -5,13 +5,10 @@ * 2.0. */ import type { ComponentType } from 'react'; -import React, { memo } from 'react'; +import React, { memo, useCallback, useMemo } from 'react'; import { Route } from '@kbn/kibana-react-plugin/public'; import type { DocLinks } from '@kbn/doc-links'; import { NoPrivilegesPage } from '../../../common/components/no_privileges'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import { NoPermissions } from '../no_permissons'; -import { MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH } from '../../common/constants'; export interface PrivilegedRouteProps { path: string; @@ -20,22 +17,18 @@ export interface PrivilegedRouteProps { } export const PrivilegedRoute = memo(({ component, hasPrivilege, path }: PrivilegedRouteProps) => { - const isEndpointRbacEnabled = useIsExperimentalFeatureEnabled('endpointRbacEnabled'); - const isEndpointRbacV1Enabled = useIsExperimentalFeatureEnabled('endpointRbacV1Enabled'); + const docLinkSelector = useCallback((docLinks: DocLinks) => { + return docLinks.securitySolution.privileges; + }, []); - const docLinkSelector = (docLinks: DocLinks) => docLinks.securitySolution.privileges; + let componentToRender = useMemo(() => { + if (!hasPrivilege) { + // eslint-disable-next-line react/display-name + componentToRender = () => ; + } - let componentToRender = component; - - if (!hasPrivilege) { - const shouldUseMissingPrivilegesScreen = - isEndpointRbacEnabled || - (isEndpointRbacV1Enabled && path === MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH); - - componentToRender = shouldUseMissingPrivilegesScreen - ? () => - : NoPermissions; - } + return component; + }, [component, docLinkSelector, hasPrivilege]); return ; }); diff --git a/x-pack/plugins/security_solution/public/management/links.test.ts b/x-pack/plugins/security_solution/public/management/links.test.ts index 68510306af6b5..664bd562ec235 100644 --- a/x-pack/plugins/security_solution/public/management/links.test.ts +++ b/x-pack/plugins/security_solution/public/management/links.test.ts @@ -146,9 +146,6 @@ describe('links', () => { fakeHttpServices.get.mockResolvedValue({ total: 0 }); licenseServiceMock.isPlatinumPlus.mockReturnValue(false); - ExperimentalFeaturesService.init({ - experimentalFeatures: { ...allowedExperimentalValues, endpointRbacEnabled: true }, - }); const filteredLinks = await getManagementFilteredLinks( coreMockStarted, @@ -187,9 +184,6 @@ describe('links', () => { fakeHttpServices.get.mockResolvedValue({ total: 100 }); licenseServiceMock.isPlatinumPlus.mockReturnValue(false); - ExperimentalFeaturesService.init({ - experimentalFeatures: { ...allowedExperimentalValues, endpointRbacEnabled: true }, - }); const filteredLinks = await getManagementFilteredLinks( coreMockStarted, @@ -222,31 +216,7 @@ describe('links', () => { }); }); - // this can be removed after removing endpointRbacEnabled feature flag - describe('without endpointRbacEnabled', () => { - beforeAll(() => { - ExperimentalFeaturesService.init({ - experimentalFeatures: { ...allowedExperimentalValues, endpointRbacEnabled: false }, - }); - }); - - it('shows Trusted Applications for non-superuser, too', async () => { - (calculateEndpointAuthz as jest.Mock).mockReturnValue(getEndpointAuthzInitialStateMock()); - - const filteredLinks = await getManagementFilteredLinks(coreMockStarted, getPlugins([])); - - expect(filteredLinks).toEqual(links); - }); - }); - - // this can be the default after removing endpointRbacEnabled feature flag - describe('with endpointRbacEnabled', () => { - beforeAll(() => { - ExperimentalFeaturesService.init({ - experimentalFeatures: { ...allowedExperimentalValues, endpointRbacEnabled: true }, - }); - }); - + describe('RBAC checks', () => { it('should return all links for user with all sub-feature privileges', async () => { (calculateEndpointAuthz as jest.Mock).mockReturnValue(getEndpointAuthzInitialStateMock()); diff --git a/x-pack/plugins/security_solution/public/management/links.ts b/x-pack/plugins/security_solution/public/management/links.ts index 07a559f92927f..daf0df2d4736f 100644 --- a/x-pack/plugins/security_solution/public/management/links.ts +++ b/x-pack/plugins/security_solution/public/management/links.ts @@ -60,7 +60,6 @@ import { IconHostIsolation } from './icons/host_isolation'; import { IconSiemRules } from './icons/siem_rules'; import { IconTrustedApplications } from './icons/trusted_applications'; import { HostIsolationExceptionsApiClient } from './pages/host_isolation_exceptions/host_isolation_exceptions_api_client'; -import { ExperimentalFeaturesService } from '../common/experimental_features_service'; const categories = [ { @@ -240,14 +239,8 @@ export const getManagementFilteredLinks = async ( plugins: StartPlugins ): Promise => { const fleetAuthz = plugins.fleet?.authz; - - const { endpointRbacEnabled, endpointRbacV1Enabled } = ExperimentalFeaturesService.get(); - const isEndpointRbacEnabled = endpointRbacEnabled || endpointRbacV1Enabled; - const linksToExclude: SecurityPageName[] = []; - const currentUser = await plugins.security.authc.getCurrentUser(); - const isPlatinumPlus = licenseService.isPlatinumPlus(); let hasHostIsolationExceptions: boolean = isPlatinumPlus; @@ -263,7 +256,7 @@ export const getManagementFilteredLinks = async ( fleetAuthz && hasKibanaPrivilege( fleetAuthz, - isEndpointRbacEnabled, + true, currentUser.roles.includes('superuser'), 'readHostIsolationExceptions' ) @@ -287,7 +280,7 @@ export const getManagementFilteredLinks = async ( licenseService, fleetAuthz, currentUser.roles, - isEndpointRbacEnabled, + true, hasHostIsolationExceptions ) : getEndpointAuthzInitialState(); diff --git a/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx index a6e98483a03a6..d0cbd71e187c5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx @@ -13,8 +13,6 @@ import type { AppContextTestRender } from '../../../common/mock/endpoint'; import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; import { useUserPrivileges } from '../../../common/components/user_privileges'; import { endpointPageHttpMock } from '../endpoint_hosts/mocks'; -import { ExperimentalFeaturesService } from '../../../common/experimental_features_service'; -import { allowedExperimentalValues } from '../../../../common/experimental_features'; jest.mock('../../../common/components/user_privileges'); @@ -24,12 +22,6 @@ describe('when in the Administration tab', () => { let render: () => ReturnType; const mockedContext = createAppRootMockRenderer(); - beforeAll(() => { - ExperimentalFeaturesService.init({ - experimentalFeatures: { ...allowedExperimentalValues }, - }); - }); - beforeEach(() => { endpointPageHttpMock(mockedContext.coreStart.http); render = () => mockedContext.render(); @@ -41,13 +33,6 @@ describe('when in the Administration tab', () => { }); describe('when the user has no permissions', () => { - // remove this beforeAll hook when feature flag is removed - beforeAll(() => { - ExperimentalFeaturesService.init({ - experimentalFeatures: { ...allowedExperimentalValues, endpointRbacEnabled: true }, - }); - }); - it('should display `no permission` if no `canAccessEndpointManagement`', async () => { useUserPrivilegesMock.mockReturnValue({ endpointPrivileges: { loading: false, canAccessEndpointManagement: false }, @@ -112,13 +97,6 @@ describe('when in the Administration tab', () => { }); describe('when the user has permissions', () => { - // remove this beforeAll hook when feature flag is removed - beforeAll(() => { - ExperimentalFeaturesService.init({ - experimentalFeatures: { ...allowedExperimentalValues, endpointRbacEnabled: true }, - }); - }); - it('should display the Management view if user has privileges', async () => { useUserPrivilegesMock.mockReturnValue({ endpointPrivileges: { loading: false, canReadEndpointList: true, canAccessFleet: true }, diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index 14475e1a8630d..8db3c3cd7df64 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -162,7 +162,6 @@ export class EndpointAppContextService { public async getEndpointAuthz(request: KibanaRequest): Promise { const fleetAuthz = await this.getFleetAuthzService().fromRequest(request); const userRoles = this.security?.authc.getCurrentUser(request)?.roles ?? []; - const { endpointRbacEnabled, endpointRbacV1Enabled } = this.experimentalFeatures; const isPlatinumPlus = this.getLicenseService().isPlatinumPlus(); const listClient = this.getExceptionListsClient(); @@ -174,7 +173,7 @@ export class EndpointAppContextService { this.getLicenseService(), fleetAuthz, userRoles, - endpointRbacEnabled || endpointRbacV1Enabled, + true, hasExceptionsListItems ); } diff --git a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts index 96ed4732ae51e..3302d396cb3d5 100644 --- a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts +++ b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts @@ -139,26 +139,18 @@ export const getSecurityBaseKibanaFeature = ( }); function getSubFeatures(experimentalFeatures: ExperimentalFeatures) { - const subFeatures: SubFeatureConfig[] = []; + const subFeatures: SubFeatureConfig[] = [ + endpointListSubFeature, + trustedApplicationsSubFeature, + hostIsolationExceptionsSubFeature, + blocklistSubFeature, + eventFiltersSubFeature, + policyManagementSubFeature, + responseActionsHistorySubFeature, + hostIsolationSubFeature, + processOperationsSubFeature, + ]; - if (experimentalFeatures.endpointRbacEnabled) { - subFeatures.push( - endpointListSubFeature, - trustedApplicationsSubFeature, - hostIsolationExceptionsSubFeature, - blocklistSubFeature, - eventFiltersSubFeature, - policyManagementSubFeature - ); - } - - if (experimentalFeatures.endpointRbacEnabled || experimentalFeatures.endpointRbacV1Enabled) { - subFeatures.push( - responseActionsHistorySubFeature, - hostIsolationSubFeature, - processOperationsSubFeature - ); - } if (experimentalFeatures.responseActionGetFileEnabled) { subFeatures.push(fileOperationsSubFeature); } diff --git a/x-pack/test/security_solution_endpoint_api_int/config.ts b/x-pack/test/security_solution_endpoint_api_int/config.ts index aaae0787d3c82..9c418ec889fe0 100644 --- a/x-pack/test/security_solution_endpoint_api_int/config.ts +++ b/x-pack/test/security_solution_endpoint_api_int/config.ts @@ -33,7 +33,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.fleet.enableExperimental.0=diagnosticFileUploadEnabled`, // this will be removed in 8.7 when the artifacts RBAC is released `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'endpointRbacEnabled', 'responseActionGetFileEnabled', 'responseActionExecuteEnabled', ])}`, From 200579c7706192ebd62c65d3e67a96a5a4ee9177 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 16:25:39 -0400 Subject: [PATCH 06/16] Remove `endpointRbacV1Enabled` feature flag --- .../security_solution/common/experimental_features.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index fcb1c650e6290..08692c4af8bdb 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -66,11 +66,6 @@ export const allowedExperimentalValues = Object.freeze({ */ endpointResponseActionsEnabled: false, - /** - * Enables endpoint package level rbac for response actions only. - * if endpointRbacEnabled is enabled, it will take precedence. - */ - endpointRbacV1Enabled: true, /** * Enables the alert details page currently only accessible via the alert details flyout and alert table context menu */ From 0664fdec4bb29c2acbefa9167d880d976851fb32 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 16:30:22 -0400 Subject: [PATCH 07/16] Remove `responseActionGetFileEnabled` feature flag --- .../common/experimental_features.ts | 5 ---- .../lib/console_commands_definition.ts | 11 +++----- .../console_commands_definition.test.tsx | 1 - .../components/hooks.tsx | 5 ---- .../security_solution/server/config.mock.ts | 2 -- .../server/endpoint/routes/actions/index.ts | 8 ++---- .../routes/actions/response_actions.ts | 27 +++++++++---------- .../app_features/security_kibana_features.ts | 4 +-- .../config.ts | 1 - 9 files changed, 18 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 08692c4af8bdb..bf3bb8c8a44de 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -71,11 +71,6 @@ export const allowedExperimentalValues = Object.freeze({ */ alertDetailsPageEnabled: false, - /** - * Enables the `get-file` endpoint response action - */ - responseActionGetFileEnabled: true, - /** * Enables the `execute` endpoint response action */ diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts index b3a7a8d4c813a..1d34cb13e0a23 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts @@ -143,7 +143,6 @@ export const getEndpointConsoleCommands = ({ }): CommandDefinition[] => { const featureFlags = ExperimentalFeaturesService.get(); - const isGetFileEnabled = featureFlags.responseActionGetFileEnabled; const isExecuteEnabled = featureFlags.responseActionExecuteEnabled; const isUploadEnabled = featureFlags.responseActionUploadEnabled; @@ -379,11 +378,7 @@ export const getEndpointConsoleCommands = ({ helpDisabled: doesEndpointSupportCommand('processes') === false, helpHidden: !getRbacControl({ commandName: 'processes', privileges: endpointPrivileges }), }, - ]; - - // `get-file` is currently behind feature flag - if (isGetFileEnabled) { - consoleCommands.push({ + { name: 'get-file', about: getCommandAboutInfo({ aboutInfo: i18n.translate('xpack.securitySolution.endpointConsoleCommands.getFile.about', { @@ -429,8 +424,8 @@ export const getEndpointConsoleCommands = ({ commandName: 'get-file', privileges: endpointPrivileges, }), - }); - } + }, + ]; // `execute` is currently behind feature flag // planned for 8.8 diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx index f5e96f0e8a706..58bfeb6c59d81 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx @@ -26,7 +26,6 @@ describe('When displaying Endpoint Response Actions', () => { const testSetup = getConsoleTestSetup(); testSetup.setExperimentalFlag({ - responseActionGetFileEnabled: true, responseActionExecuteEnabled: true, }); diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx index 91f5a9439b334..b0fe55d376caa 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx @@ -247,11 +247,6 @@ export const useActionsLogFilter = ({ : RESPONSE_ACTION_API_COMMANDS_NAMES.filter((commandName) => { const featureFlags = ExperimentalFeaturesService.get(); - // `get-file` is currently behind FF - if (commandName === 'get-file' && !featureFlags.responseActionGetFileEnabled) { - return false; - } - // TODO: remove this when `execute` is no longer behind FF // planned for 8.8 if (commandName === 'execute' && !featureFlags.responseActionExecuteEnabled) { diff --git a/x-pack/plugins/security_solution/server/config.mock.ts b/x-pack/plugins/security_solution/server/config.mock.ts index ca655d103e279..bc17aa278b86c 100644 --- a/x-pack/plugins/security_solution/server/config.mock.ts +++ b/x-pack/plugins/security_solution/server/config.mock.ts @@ -12,8 +12,6 @@ import type { ConfigType } from './config'; export const createMockConfig = (): ConfigType => { const enableExperimental: Array = [ - // Remove property below once `get-file` FF is enabled or removed - 'responseActionGetFileEnabled', // remove property below once `execute` FF is enabled or removed 'responseActionExecuteEnabled', 'responseActionUploadEnabled', diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts index 1f96cb4dff64a..6587a6446a52c 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts @@ -29,10 +29,6 @@ export function registerActionRoutes( registerActionListRoutes(router, endpointContext); registerActionDetailsRoutes(router, endpointContext); registerResponseActionRoutes(router, endpointContext); - - // APIs specific to `get-file` are behind FF - if (endpointContext.experimentalFeatures.responseActionGetFileEnabled) { - registerActionFileDownloadRoutes(router, endpointContext); - registerActionFileInfoRoute(router, endpointContext); - } + registerActionFileDownloadRoutes(router, endpointContext); + registerActionFileInfoRoute(router, endpointContext); } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts index 0348227561677..c5ba97eaa572a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts @@ -145,21 +145,18 @@ export function registerResponseActionRoutes( ) ); - // `get-file` currently behind FF - if (endpointContext.experimentalFeatures.responseActionGetFileEnabled) { - router.post( - { - path: GET_FILE_ROUTE, - validate: EndpointActionGetFileSchema, - options: { authRequired: true, tags: ['access:securitySolution'] }, - }, - withEndpointAuthz( - { all: ['canWriteFileOperations'] }, - logger, - responseActionRequestHandler(endpointContext, 'get-file') - ) - ); - } + router.post( + { + path: GET_FILE_ROUTE, + validate: EndpointActionGetFileSchema, + options: { authRequired: true, tags: ['access:securitySolution'] }, + }, + withEndpointAuthz( + { all: ['canWriteFileOperations'] }, + logger, + responseActionRequestHandler(endpointContext, 'get-file') + ) + ); // `execute` currently behind FF (planned for 8.8) if (endpointContext.experimentalFeatures.responseActionExecuteEnabled) { diff --git a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts index 3302d396cb3d5..365e6c57ff9a3 100644 --- a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts +++ b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts @@ -149,11 +149,9 @@ function getSubFeatures(experimentalFeatures: ExperimentalFeatures) { responseActionsHistorySubFeature, hostIsolationSubFeature, processOperationsSubFeature, + fileOperationsSubFeature, ]; - if (experimentalFeatures.responseActionGetFileEnabled) { - subFeatures.push(fileOperationsSubFeature); - } // planned for 8.8 if (experimentalFeatures.responseActionExecuteEnabled) { subFeatures.push(executeActionSubFeature); diff --git a/x-pack/test/security_solution_endpoint_api_int/config.ts b/x-pack/test/security_solution_endpoint_api_int/config.ts index 9c418ec889fe0..bd4201c1c0d11 100644 --- a/x-pack/test/security_solution_endpoint_api_int/config.ts +++ b/x-pack/test/security_solution_endpoint_api_int/config.ts @@ -33,7 +33,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.fleet.enableExperimental.0=diagnosticFileUploadEnabled`, // this will be removed in 8.7 when the artifacts RBAC is released `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'responseActionGetFileEnabled', 'responseActionExecuteEnabled', ])}`, ], From 24725f3f150d440f2b035eb88dd9afaec5215ea6 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 16:36:27 -0400 Subject: [PATCH 08/16] Remove `responseActionExecuteEnabled` feature flag --- .../common/experimental_features.ts | 7 +---- .../lib/console_commands_definition.ts | 12 +++------ .../console_commands_definition.test.tsx | 4 --- .../components/hooks.tsx | 6 ----- .../security_solution/server/config.mock.ts | 6 +---- .../routes/actions/response_actions.ts | 27 +++++++++---------- .../app_features/security_kibana_features.ts | 20 ++++---------- .../config.ts | 6 ++--- 8 files changed, 24 insertions(+), 64 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index bf3bb8c8a44de..0de25da085406 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -72,12 +72,7 @@ export const allowedExperimentalValues = Object.freeze({ alertDetailsPageEnabled: false, /** - * Enables the `execute` endpoint response action - */ - responseActionExecuteEnabled: true, - - /** - * Enables the `upload` endpoint response action + * Enables the `upload` endpoint response action (v8.9) */ responseActionUploadEnabled: false, diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts index 1d34cb13e0a23..fd64cff764966 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts @@ -143,7 +143,6 @@ export const getEndpointConsoleCommands = ({ }): CommandDefinition[] => { const featureFlags = ExperimentalFeaturesService.get(); - const isExecuteEnabled = featureFlags.responseActionExecuteEnabled; const isUploadEnabled = featureFlags.responseActionUploadEnabled; const doesEndpointSupportCommand = (commandName: ConsoleResponseActionCommands) => { @@ -425,12 +424,7 @@ export const getEndpointConsoleCommands = ({ privileges: endpointPrivileges, }), }, - ]; - - // `execute` is currently behind feature flag - // planned for 8.8 - if (isExecuteEnabled) { - consoleCommands.push({ + { name: 'execute', about: getCommandAboutInfo({ aboutInfo: i18n.translate('xpack.securitySolution.endpointConsoleCommands.execute.about', { @@ -482,8 +476,8 @@ export const getEndpointConsoleCommands = ({ commandName: 'execute', privileges: endpointPrivileges, }), - }); - } + }, + ]; // `upload` command // planned for 8.9 diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx index 58bfeb6c59d81..4b1d26a6e243f 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx @@ -25,10 +25,6 @@ describe('When displaying Endpoint Response Actions', () => { beforeEach(() => { const testSetup = getConsoleTestSetup(); - testSetup.setExperimentalFlag({ - responseActionExecuteEnabled: true, - }); - const endpointMetadata = new EndpointMetadataGenerator().generate(); const commands = getEndpointConsoleCommands({ endpointAgentId: '123', diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx index b0fe55d376caa..bab16f27dbace 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx @@ -247,12 +247,6 @@ export const useActionsLogFilter = ({ : RESPONSE_ACTION_API_COMMANDS_NAMES.filter((commandName) => { const featureFlags = ExperimentalFeaturesService.get(); - // TODO: remove this when `execute` is no longer behind FF - // planned for 8.8 - if (commandName === 'execute' && !featureFlags.responseActionExecuteEnabled) { - return false; - } - // upload - v8.9 if (commandName === 'upload' && !featureFlags.responseActionUploadEnabled) { return false; diff --git a/x-pack/plugins/security_solution/server/config.mock.ts b/x-pack/plugins/security_solution/server/config.mock.ts index bc17aa278b86c..88ce4c7b91910 100644 --- a/x-pack/plugins/security_solution/server/config.mock.ts +++ b/x-pack/plugins/security_solution/server/config.mock.ts @@ -11,11 +11,7 @@ import { parseExperimentalConfigValue } from '../common/experimental_features'; import type { ConfigType } from './config'; export const createMockConfig = (): ConfigType => { - const enableExperimental: Array = [ - // remove property below once `execute` FF is enabled or removed - 'responseActionExecuteEnabled', - 'responseActionUploadEnabled', - ]; + const enableExperimental: Array = ['responseActionUploadEnabled']; return { [SIGNALS_INDEX_KEY]: DEFAULT_SIGNALS_INDEX, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts index c5ba97eaa572a..1d82c9faa5461 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts @@ -158,21 +158,18 @@ export function registerResponseActionRoutes( ) ); - // `execute` currently behind FF (planned for 8.8) - if (endpointContext.experimentalFeatures.responseActionExecuteEnabled) { - router.post( - { - path: EXECUTE_ROUTE, - validate: ExecuteActionRequestSchema, - options: { authRequired: true, tags: ['access:securitySolution'] }, - }, - withEndpointAuthz( - { all: ['canWriteExecuteOperations'] }, - logger, - responseActionRequestHandler(endpointContext, 'execute') - ) - ); - } + router.post( + { + path: EXECUTE_ROUTE, + validate: ExecuteActionRequestSchema, + options: { authRequired: true, tags: ['access:securitySolution'] }, + }, + withEndpointAuthz( + { all: ['canWriteExecuteOperations'] }, + logger, + responseActionRequestHandler(endpointContext, 'execute') + ) + ); registerActionFileUploadRoute(router, endpointContext); } diff --git a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts index 365e6c57ff9a3..fb2dd3f907fde 100644 --- a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts +++ b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; -import type { KibanaFeatureConfig, SubFeatureConfig } from '@kbn/features-plugin/common'; +import type { KibanaFeatureConfig } from '@kbn/features-plugin/common'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common'; import { EXCEPTION_LIST_NAMESPACE_AGNOSTIC } from '@kbn/securitysolution-list-constants'; @@ -135,11 +135,7 @@ export const getSecurityBaseKibanaFeature = ( ui: ['show'], }, }, - subFeatures: getSubFeatures(experimentalFeatures), -}); - -function getSubFeatures(experimentalFeatures: ExperimentalFeatures) { - const subFeatures: SubFeatureConfig[] = [ + subFeatures: [ endpointListSubFeature, trustedApplicationsSubFeature, hostIsolationExceptionsSubFeature, @@ -150,15 +146,9 @@ function getSubFeatures(experimentalFeatures: ExperimentalFeatures) { hostIsolationSubFeature, processOperationsSubFeature, fileOperationsSubFeature, - ]; - - // planned for 8.8 - if (experimentalFeatures.responseActionExecuteEnabled) { - subFeatures.push(executeActionSubFeature); - } - - return subFeatures; -} + executeActionSubFeature, + ], +}); // maps the AppFeatures keys to Kibana privileges export const getSecurityAppFeaturesConfig = (): AppFeaturesSecurityConfig => { diff --git a/x-pack/test/security_solution_endpoint_api_int/config.ts b/x-pack/test/security_solution_endpoint_api_int/config.ts index bd4201c1c0d11..0f2f245378a3c 100644 --- a/x-pack/test/security_solution_endpoint_api_int/config.ts +++ b/x-pack/test/security_solution_endpoint_api_int/config.ts @@ -31,10 +31,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.fleet.packages.0.version=latest`, // this will be removed in 8.7 when the file upload feature is released `--xpack.fleet.enableExperimental.0=diagnosticFileUploadEnabled`, - // this will be removed in 8.7 when the artifacts RBAC is released - `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'responseActionExecuteEnabled', - ])}`, + // set any experimental feature flags for testing + `--xpack.securitySolution.enableExperimental=${JSON.stringify([])}`, ], }, }; From 3dd0e0aeea7511d55b58ca1328449be779038825 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Fri, 2 Jun 2023 17:17:45 -0400 Subject: [PATCH 09/16] fix cypress ci config --- x-pack/test/defend_workflows_cypress/endpoint_config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/defend_workflows_cypress/endpoint_config.ts b/x-pack/test/defend_workflows_cypress/endpoint_config.ts index a6e3f15934b1a..a1e437a442a87 100644 --- a/x-pack/test/defend_workflows_cypress/endpoint_config.ts +++ b/x-pack/test/defend_workflows_cypress/endpoint_config.ts @@ -16,7 +16,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { const config = defendWorkflowsCypressConfig.getAll(); const hostIp = getLocalhostRealIp(); - const enabledFeatureFlags: Array = ['responseActionExecuteEnabled']; + const enabledFeatureFlags: Array = []; return { ...config, From e046f8f642c61c842cc38370f1c227f39edce2f2 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 5 Jun 2023 11:33:57 -0400 Subject: [PATCH 10/16] Remove `pendingActionResponsesWithAck` feature flag --- .../common/experimental_features.ts | 4 +- .../endpoint/routes/actions/status.test.ts | 460 +++++++++--------- .../server/endpoint/routes/actions/status.ts | 3 +- .../actions/pending_actions_summary.ts | 11 +- .../factory/hosts/details/helpers.ts | 10 +- 5 files changed, 231 insertions(+), 257 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 0de25da085406..015a36c5b4317 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -16,8 +16,10 @@ export const allowedExperimentalValues = Object.freeze({ tGridEventRenderedViewEnabled: true, excludePoliciesInFilterEnabled: false, kubernetesEnabled: true, - pendingActionResponsesWithAck: true, + + // TODO:PT remove policyResponseInFleetEnabled: true, + chartEmbeddablesEnabled: true, donutChartEmbeddablesEnabled: false, // Depends on https://github.com/elastic/kibana/issues/136409 item 2 - 6 alertsPreviewChartEmbeddablesEnabled: false, // Depends on https://github.com/elastic/kibana/issues/136409 item 9 diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts index c04d9e34a7c4d..fca197b22c748 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.test.ts @@ -49,7 +49,7 @@ describe('Endpoint Pending Action Summary API', () => { endpointResponses: LogsEndpointActionResponse[] ) => void; - const setupRouteHandler = (pendingActionResponsesWithAck: boolean = true): void => { + const setupRouteHandler = (): void => { const esClientMock = elasticsearchServiceMock.createScopedClusterClient(); const routerMock = httpServiceMock.createRouter(); @@ -71,7 +71,6 @@ describe('Endpoint Pending Action Summary API', () => { service: endpointAppContextService, experimentalFeatures: { ...endpointContextMock.experimentalFeatures, - pendingActionResponsesWithAck, }, }); @@ -126,6 +125,10 @@ describe('Endpoint Pending Action Summary API', () => { }; }; + beforeEach(() => { + setupRouteHandler(); + }); + afterEach(() => { if (endpointAppContextService) { endpointAppContextService.stop(); @@ -158,261 +161,240 @@ describe('Endpoint Pending Action Summary API', () => { }); }); - describe.each([ - ['when pendingActionResponsesWithAck is TRUE', true], - ['when pendingActionResponsesWithAck is FALSE', false], - ])('response %s', (_, pendingActionResponsesWithAck) => { - const getExpected = (value: number): number => { - return pendingActionResponsesWithAck ? value : 0; - }; - - beforeEach(() => { - setupRouteHandler(pendingActionResponsesWithAck); + it('should include agent IDs in the output, even if they have no actions', async () => { + const mockID = 'XYZABC-000'; + havingActionsAndResponses([], []); + const response = await getPendingStatus({ + query: { + agent_ids: [mockID], + }, }); + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + }); - it('should include agent IDs in the output, even if they have no actions', async () => { - const mockID = 'XYZABC-000'; - havingActionsAndResponses([], []); - const response = await getPendingStatus({ - query: { - agent_ids: [mockID], - }, - }); - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + it('should include total counts for large (more than a page) action counts', async () => { + const mockID = 'XYZABC-000'; + const actions: LogsEndpointAction[] = Array.from({ length: 1400 }, () => + endpointActionGenerator.generate({ + agent: { id: [mockID] }, + EndpointActions: { data: { command: 'isolate' } }, + }) + ); + havingActionsAndResponses(actions, []); + + const response = await getPendingStatus({ + query: { + agent_ids: [mockID], + }, }); - it('should include total counts for large (more than a page) action counts', async () => { - const mockID = 'XYZABC-000'; - const actions: LogsEndpointAction[] = Array.from({ length: 1400 }, () => + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual( + 1400 + ); + }); + + it('should respond with a valid pending action', async () => { + const mockID = 'XYZABC-000'; + havingActionsAndResponses( + [ endpointActionGenerator.generate({ agent: { id: [mockID] }, - EndpointActions: { data: { command: 'isolate' } }, - }) - ); - havingActionsAndResponses(actions, []); - - const response = await getPendingStatus({ - query: { - agent_ids: [mockID], - }, - }); - - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual( - getExpected(1400) - ); + }), + ], + [] + ); + const response = await getPendingStatus({ + query: { + agent_ids: [mockID], + }, }); - - it('should respond with a valid pending action', async () => { - const mockID = 'XYZABC-000'; - havingActionsAndResponses( - [ - endpointActionGenerator.generate({ - agent: { id: [mockID] }, - }), - ], - [] - ); - const response = await getPendingStatus({ - query: { - agent_ids: [mockID], - }, - }); - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + }); + it('should include a total count of a pending action', async () => { + const mockID = 'XYZABC-000'; + havingActionsAndResponses( + [ + endpointActionGenerator.generate({ + agent: { id: [mockID] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + endpointActionGenerator.generate({ + agent: { id: [mockID] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + ], + [] + ); + const response = await getPendingStatus({ + query: { + agent_ids: [mockID], + }, }); - it('should include a total count of a pending action', async () => { - const mockID = 'XYZABC-000'; - havingActionsAndResponses( - [ - endpointActionGenerator.generate({ - agent: { id: [mockID] }, - EndpointActions: { data: { command: 'isolate' } }, - }), + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual(2); + }); + it('should show multiple pending actions, and their counts', async () => { + const mockID = 'XYZABC-000'; + havingActionsAndResponses( + Array.from( + ['isolate', 'isolate', 'isolate', 'unisolate', 'unisolate'], + (command) => endpointActionGenerator.generate({ agent: { id: [mockID] }, - EndpointActions: { data: { command: 'isolate' } }, - }), - ], - [] - ); - const response = await getPendingStatus({ - query: { - agent_ids: [mockID], - }, - }); - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual( - getExpected(2) - ); - }); - it('should show multiple pending actions, and their counts', async () => { - const mockID = 'XYZABC-000'; - havingActionsAndResponses( - Array.from( - ['isolate', 'isolate', 'isolate', 'unisolate', 'unisolate'], - (command) => - endpointActionGenerator.generate({ - agent: { id: [mockID] }, - EndpointActions: { data: { command } }, - }) - ), - [] - ); - const response = await getPendingStatus({ - query: { - agent_ids: [mockID], - }, - }); - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual( - getExpected(3) - ); - expect( - (response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.unisolate - ).toEqual(getExpected(2)); + EndpointActions: { data: { command } }, + }) + ), + [] + ); + const response = await getPendingStatus({ + query: { + agent_ids: [mockID], + }, }); - it('should calculate correct pending counts from grouped/bulked actions', async () => { - const mockID = 'XYZABC-000'; - havingActionsAndResponses( - [ - endpointActionGenerator.generate({ - agent: { id: [mockID, 'IRRELEVANT-OTHER-AGENT', 'ANOTHER-POSSIBLE-AGENT'] }, - EndpointActions: { data: { command: 'isolate' } }, - }), - endpointActionGenerator.generate({ - agent: { id: [mockID, 'YET-ANOTHER-AGENT-ID'] }, - EndpointActions: { data: { command: 'isolate' } }, - }), - endpointActionGenerator.generate({ - agent: { id: ['YET-ANOTHER-AGENT-ID'] }, - EndpointActions: { data: { command: 'isolate' } }, - }), - ], - [] - ); - const response = await getPendingStatus({ - query: { - agent_ids: [mockID], - }, - }); - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual( - getExpected(2) - ); + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual(3); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.unisolate).toEqual( + 2 + ); + }); + it('should calculate correct pending counts from grouped/bulked actions', async () => { + const mockID = 'XYZABC-000'; + havingActionsAndResponses( + [ + endpointActionGenerator.generate({ + agent: { id: [mockID, 'IRRELEVANT-OTHER-AGENT', 'ANOTHER-POSSIBLE-AGENT'] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + endpointActionGenerator.generate({ + agent: { id: [mockID, 'YET-ANOTHER-AGENT-ID'] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + endpointActionGenerator.generate({ + agent: { id: ['YET-ANOTHER-AGENT-ID'] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + ], + [] + ); + const response = await getPendingStatus({ + query: { + agent_ids: [mockID], + }, }); + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockID); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual(2); + }); - it('should exclude actions that have responses from the pending count', async () => { - const mockAgentID = 'XYZABC-000'; - const actionID = 'some-known-actionid'; - havingActionsAndResponses( - [ - endpointActionGenerator.generate({ - agent: { id: [mockAgentID] }, - EndpointActions: { data: { command: 'isolate' } }, - }), - endpointActionGenerator.generate({ - agent: { id: [mockAgentID] }, - EndpointActions: { action_id: actionID, data: { command: 'isolate' } }, - }), - ], - [ - endpointActionGenerator.generateResponse({ - agent: { id: [mockAgentID] }, - EndpointActions: { action_id: actionID, data: { command: 'isolate' } }, - }), - ] - ); - (endpointAppContextService.getEndpointMetadataService as jest.Mock) = jest - .fn() - .mockReturnValue({ - findHostMetadataForFleetAgents: jest.fn().mockResolvedValue([]), - }); - const response = await getPendingStatus({ - query: { - agent_ids: [mockAgentID], - }, + it('should exclude actions that have responses from the pending count', async () => { + const mockAgentID = 'XYZABC-000'; + const actionID = 'some-known-actionid'; + havingActionsAndResponses( + [ + endpointActionGenerator.generate({ + agent: { id: [mockAgentID] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + endpointActionGenerator.generate({ + agent: { id: [mockAgentID] }, + EndpointActions: { action_id: actionID, data: { command: 'isolate' } }, + }), + ], + [ + endpointActionGenerator.generateResponse({ + agent: { id: [mockAgentID] }, + EndpointActions: { action_id: actionID, data: { command: 'isolate' } }, + }), + ] + ); + (endpointAppContextService.getEndpointMetadataService as jest.Mock) = jest + .fn() + .mockReturnValue({ + findHostMetadataForFleetAgents: jest.fn().mockResolvedValue([]), }); - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockAgentID); - expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual( - getExpected(1) - ); + const response = await getPendingStatus({ + query: { + agent_ids: [mockAgentID], + }, }); + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(1); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].agent_id).toEqual(mockAgentID); + expect((response.ok.mock.calls[0][0]?.body as any)?.data[0].pending_actions.isolate).toEqual(1); + }); - it('should have accurate counts for multiple agents, bulk actions, and responses', async () => { - const agentOne = 'XYZABC-000'; - const agentTwo = 'DEADBEEF'; - const agentThree = 'IDIDIDID'; - - const actionTwoID = 'ID-TWO'; - havingActionsAndResponses( - [ - endpointActionGenerator.generate({ - agent: { id: [agentOne, agentTwo, agentThree] }, - EndpointActions: { data: { command: 'isolate' } }, - }), - endpointActionGenerator.generate({ - agent: { id: [agentTwo, agentThree] }, - EndpointActions: { data: { command: 'isolate' }, action_id: actionTwoID }, - }), - endpointActionGenerator.generate({ - agent: { id: [agentThree] }, - EndpointActions: { data: { command: 'isolate' } }, - }), - ], + it('should have accurate counts for multiple agents, bulk actions, and responses', async () => { + const agentOne = 'XYZABC-000'; + const agentTwo = 'DEADBEEF'; + const agentThree = 'IDIDIDID'; - [ - endpointActionGenerator.generateResponse({ - agent: { id: [agentThree] }, - EndpointActions: { - action_id: actionTwoID, - }, - }), - ] - ); - (endpointAppContextService.getEndpointMetadataService as jest.Mock) = jest - .fn() - .mockReturnValue({ - findHostMetadataForFleetAgents: jest.fn().mockResolvedValue([]), - }); - const response = await getPendingStatus({ - query: { - agent_ids: [agentOne, agentTwo, agentThree], - }, - }); - expect(response.ok).toBeCalled(); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(3); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toContainEqual({ - agent_id: agentOne, - pending_actions: { - isolate: getExpected(1), - }, - }); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toContainEqual({ - agent_id: agentTwo, - pending_actions: { - isolate: getExpected(2), - }, - }); - expect((response.ok.mock.calls[0][0]?.body as any)?.data).toContainEqual({ - agent_id: agentThree, - pending_actions: { - isolate: getExpected(2), // present in all three actions, but second one has a response, therefore not pending - }, + const actionTwoID = 'ID-TWO'; + havingActionsAndResponses( + [ + endpointActionGenerator.generate({ + agent: { id: [agentOne, agentTwo, agentThree] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + endpointActionGenerator.generate({ + agent: { id: [agentTwo, agentThree] }, + EndpointActions: { data: { command: 'isolate' }, action_id: actionTwoID }, + }), + endpointActionGenerator.generate({ + agent: { id: [agentThree] }, + EndpointActions: { data: { command: 'isolate' } }, + }), + ], + + [ + endpointActionGenerator.generateResponse({ + agent: { id: [agentThree] }, + EndpointActions: { + action_id: actionTwoID, + }, + }), + ] + ); + (endpointAppContextService.getEndpointMetadataService as jest.Mock) = jest + .fn() + .mockReturnValue({ + findHostMetadataForFleetAgents: jest.fn().mockResolvedValue([]), }); + const response = await getPendingStatus({ + query: { + agent_ids: [agentOne, agentTwo, agentThree], + }, + }); + expect(response.ok).toBeCalled(); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toHaveLength(3); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toContainEqual({ + agent_id: agentOne, + pending_actions: { + isolate: 1, + }, + }); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toContainEqual({ + agent_id: agentTwo, + pending_actions: { + isolate: 2, + }, + }); + expect((response.ok.mock.calls[0][0]?.body as any)?.data).toContainEqual({ + agent_id: agentThree, + pending_actions: { + isolate: 2, // present in all three actions, but second one has a response, therefore not pending + }, }); }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts index 2660fcd37103e..eb392e546d396 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts @@ -59,8 +59,7 @@ export const actionStatusRequestHandler = function ( esClient, endpointContext.service.getEndpointMetadataService(), logger, - agentIDs, - endpointContext.experimentalFeatures.pendingActionResponsesWithAck + agentIDs ); return res.ok({ diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/pending_actions_summary.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/pending_actions_summary.ts index a2aafaab57d42..543612bb5e39e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/pending_actions_summary.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/pending_actions_summary.ts @@ -24,8 +24,7 @@ export const getPendingActionsSummary = async ( metadataService: EndpointMetadataService, logger: Logger, /** The Fleet Agent IDs to be checked */ - agentIDs: string[], - isPendingActionResponsesWithAckEnabled: boolean + agentIDs: string[] ): Promise => { const { data: unExpiredActionList } = await getActionList({ esClient, @@ -60,12 +59,8 @@ export const getPendingActionsSummary = async ( for (const agentID of agentIDs) { const agentPendingActions: EndpointPendingActions['pending_actions'] = {}; const setActionAsPending = (commandName: string) => { - // Add the command to the list of pending actions, but set it to zero if the - // `pendingActionResponsesWithAck` feature flag is false. - // Otherwise, just increment the count for this command - agentPendingActions[commandName] = !isPendingActionResponsesWithAckEnabled - ? 0 - : (agentPendingActions[commandName] ?? 0) + 1; + // Add the command to the list of pending actions and increment the count for this command + agentPendingActions[commandName] = (agentPendingActions[commandName] ?? 0) + 1; }; pending.push({ diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index f7c8b9cb52be9..4472fa3c0d691 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -182,13 +182,9 @@ export const getHostEndpoint = async ( const fleetAgentId = endpointData.metadata.elastic.agent.id; const pendingActions = fleetAgentId - ? getPendingActionsSummary( - esClient.asInternalUser, - endpointMetadataService, - logger, - [fleetAgentId], - endpointContext.experimentalFeatures.pendingActionResponsesWithAck - ) + ? getPendingActionsSummary(esClient.asInternalUser, endpointMetadataService, logger, [ + fleetAgentId, + ]) .then((results) => { return results[0].pending_actions; }) From 4fcb834c386041c37b0b9a32375b553a5985ed61 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 5 Jun 2023 11:35:23 -0400 Subject: [PATCH 11/16] Remove `policyResponseInFleetEnabled` feature flag --- .../common/experimental_features.ts | 4 ---- .../security_solution/public/plugin.tsx | 23 +++++++++---------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 015a36c5b4317..c3c2bf7757a4e 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -16,10 +16,6 @@ export const allowedExperimentalValues = Object.freeze({ tGridEventRenderedViewEnabled: true, excludePoliciesInFilterEnabled: false, kubernetesEnabled: true, - - // TODO:PT remove - policyResponseInFleetEnabled: true, - chartEmbeddablesEnabled: true, donutChartEmbeddablesEnabled: false, // Depends on https://github.com/elastic/kibana/issues/136409 item 2 - 6 alertsPreviewChartEmbeddablesEnabled: false, // Depends on https://github.com/elastic/kibana/issues/136409 item 9 diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index f506a0a04d3f1..45680b4c6cd3a 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -270,18 +270,17 @@ export class Plugin implements IPlugin Date: Mon, 5 Jun 2023 11:36:44 -0400 Subject: [PATCH 12/16] delete deprecated flags for `riskyHostsEnabled` and `rickyUsersEnabled` --- .../security_solution/common/experimental_features.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index c3c2bf7757a4e..4209f6d8988cb 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -84,16 +84,6 @@ export const allowedExperimentalValues = Object.freeze({ */ securityFlyoutEnabled: false, - /** - * Keep DEPRECATED experimental flags that are documented to prevent failed upgrades. - * https://www.elastic.co/guide/en/security/current/user-risk-score.html - * https://www.elastic.co/guide/en/security/current/host-risk-score.html - * - * Issue: https://github.com/elastic/kibana/issues/146777 - */ - riskyHostsEnabled: false, // DEPRECATED - riskyUsersEnabled: false, // DEPRECATED - /* * Enables new Set of filters on the Alerts page. * From 6704bc8af6476e11566732b6dc647fc6ca8c716c Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 5 Jun 2023 11:54:06 -0400 Subject: [PATCH 13/16] adjust `getSecurityBaseKibanaSubFeatureIds()` to remove checking Feature Flags --- .../app_features/security_kibana_features.ts | 47 +++++++------------ 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts index e9a6abe7b3adb..4bf4ceed34aad 100644 --- a/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts +++ b/x-pack/plugins/security_solution/server/lib/app_features/security_kibana_features.ts @@ -8,7 +8,6 @@ import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; -import type { KibanaFeatureConfig } from '@kbn/features-plugin/common'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common'; import { EXCEPTION_LIST_NAMESPACE_AGNOSTIC } from '@kbn/securitysolution-list-constants'; import { @@ -20,10 +19,10 @@ import { SAVED_QUERY_RULE_TYPE_ID, THRESHOLD_RULE_TYPE_ID, } from '@kbn/securitysolution-rules'; +import type { ExperimentalFeatures } from '../../../common'; +import { SecuritySubFeatureId } from './security_kibana_sub_features'; import { APP_ID, LEGACY_NOTIFICATIONS_ID, SERVER_APP_ID } from '../../../common/constants'; import { savedObjectTypes } from '../../saved_objects'; -import type { ExperimentalFeatures } from '../../../common/experimental_features'; -import { SecuritySubFeatureId } from './security_kibana_sub_features'; import type { AppFeaturesSecurityConfig, BaseKibanaFeatureConfig } from './types'; import { AppFeatureSecurityKey } from '../../../common/types/app_features'; @@ -124,35 +123,21 @@ export const getSecurityBaseKibanaFeature = (): BaseKibanaFeatureConfig => ({ }); export const getSecurityBaseKibanaSubFeatureIds = ( - experimentalFeatures: ExperimentalFeatures + _: ExperimentalFeatures // currently un-used, but left here as a convenience for possible future use ): SecuritySubFeatureId[] => { - const subFeatureIds: SecuritySubFeatureId[] = []; - - if (experimentalFeatures.endpointRbacEnabled) { - subFeatureIds.push( - SecuritySubFeatureId.endpointList, - SecuritySubFeatureId.trustedApplications, - SecuritySubFeatureId.hostIsolationExceptions, - SecuritySubFeatureId.blocklist, - SecuritySubFeatureId.eventFilters, - SecuritySubFeatureId.policyManagement - ); - } - - if (experimentalFeatures.endpointRbacEnabled || experimentalFeatures.endpointRbacV1Enabled) { - subFeatureIds.push( - SecuritySubFeatureId.responseActionsHistory, - SecuritySubFeatureId.hostIsolation, - SecuritySubFeatureId.processOperations - ); - } - if (experimentalFeatures.responseActionGetFileEnabled) { - subFeatureIds.push(SecuritySubFeatureId.fileOperations); - } - // planned for 8.8 - if (experimentalFeatures.responseActionExecuteEnabled) { - subFeatureIds.push(SecuritySubFeatureId.executeAction); - } + const subFeatureIds: SecuritySubFeatureId[] = [ + SecuritySubFeatureId.endpointList, + SecuritySubFeatureId.trustedApplications, + SecuritySubFeatureId.hostIsolationExceptions, + SecuritySubFeatureId.blocklist, + SecuritySubFeatureId.eventFilters, + SecuritySubFeatureId.policyManagement, + SecuritySubFeatureId.responseActionsHistory, + SecuritySubFeatureId.hostIsolation, + SecuritySubFeatureId.processOperations, + SecuritySubFeatureId.fileOperations, + SecuritySubFeatureId.executeAction, + ]; return subFeatureIds; }; From 574e48e68164e51f70693ba25f1bfedecba5dacb Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 5 Jun 2023 11:56:21 -0400 Subject: [PATCH 14/16] fix i18n translations --- x-pack/plugins/translations/translations/fr-FR.json | 1 - x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 3 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index ffe6d5515bb0c..a8f4e9ab6e408 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -33101,7 +33101,6 @@ "xpack.securitySolution.policy.list.subtitle": "Utiliser les politiques pour personnaliser les protections des points de terminaison et de charge de travail cloud, et d'autres configurations", "xpack.securitySolution.policy.list.title": "Politiques", "xpack.securitySolution.policy.list.updatedAt": "Dernière mise à jour", - "xpack.securitySolution.policyDetails.backToEndpointList": "Afficher tous les points de terminaison", "xpack.securitySolution.policyDetails.backToPolicyButton": "Retour à la liste des politiques", "xpack.securitySolution.policyDetails.missingArtifactAccess": "Vous ne disposez pas des autorisations Kibana requises pour utiliser l'artefact donné.", "xpack.securitySolution.policyList.packageVersionError": "Erreur lors de la récupération de la version du pack de points de terminaison", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 81add29898d3b..7b85916da1808 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -33082,7 +33082,6 @@ "xpack.securitySolution.policy.list.subtitle": "ポリシーを使用して、エンドポイントおよびクラウドワークロード保護、ならびに他の構成をカスタマイズ", "xpack.securitySolution.policy.list.title": "ポリシー", "xpack.securitySolution.policy.list.updatedAt": "最終更新", - "xpack.securitySolution.policyDetails.backToEndpointList": "すべてのエンドポイントを表示", "xpack.securitySolution.policyDetails.backToPolicyButton": "ポリシーリストに戻る", "xpack.securitySolution.policyDetails.missingArtifactAccess": "特定のアーティファクトを使用するために必要なKibana権限がありません。", "xpack.securitySolution.policyList.packageVersionError": "エンドポイントパッケージバージョンの取得エラー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 940c0f9e10879..497a4096162b2 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -33078,7 +33078,6 @@ "xpack.securitySolution.policy.list.subtitle": "使用策略定制终端和云工作负载防护及其他配置", "xpack.securitySolution.policy.list.title": "策略", "xpack.securitySolution.policy.list.updatedAt": "上次更新时间", - "xpack.securitySolution.policyDetails.backToEndpointList": "查看所有终端", "xpack.securitySolution.policyDetails.backToPolicyButton": "返回到策略列表", "xpack.securitySolution.policyDetails.missingArtifactAccess": "您没有所需 Kibana 权限,无法使用给定项目。", "xpack.securitySolution.policyList.packageVersionError": "检索终端软件包版本时出错", From 0e64cbcfcdbcc39818854e748b3da2617bfdf7f6 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 5 Jun 2023 12:05:54 -0400 Subject: [PATCH 15/16] Delete the `NoPermission` component (which referenced the need for superuser role) --- .../components/no_permissons/index.ts | 8 ---- .../no_permissons/no_permissions.tsx | 38 ------------------- 2 files changed, 46 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/management/components/no_permissons/index.ts delete mode 100644 x-pack/plugins/security_solution/public/management/components/no_permissons/no_permissions.tsx diff --git a/x-pack/plugins/security_solution/public/management/components/no_permissons/index.ts b/x-pack/plugins/security_solution/public/management/components/no_permissons/index.ts deleted file mode 100644 index 25421ba1dcd1a..0000000000000 --- a/x-pack/plugins/security_solution/public/management/components/no_permissons/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * 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. - */ - -export { NoPermissions } from './no_permissions'; diff --git a/x-pack/plugins/security_solution/public/management/components/no_permissons/no_permissions.tsx b/x-pack/plugins/security_solution/public/management/components/no_permissons/no_permissions.tsx deleted file mode 100644 index 3852cfbf73995..0000000000000 --- a/x-pack/plugins/security_solution/public/management/components/no_permissons/no_permissions.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 React, { memo } from 'react'; -import { EuiEmptyPrompt, EuiText } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -export const NoPermissions = memo(() => { - return ( - <> - - } - body={ - - - - } - /> - - ); -}); -NoPermissions.displayName = 'NoPermissions'; From 5d26ed1e4eecfa319cb1d8da4c5e9c73854cfa6c Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 5 Jun 2023 12:58:11 -0400 Subject: [PATCH 16/16] Fix PrivilegedRoute --- .../plugins/security_solution/common/experimental_features.ts | 3 +++ .../components/privileged_route/privileged_route.tsx | 4 ++-- x-pack/plugins/translations/translations/fr-FR.json | 2 -- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index ea16a97aeb575..68f4308384649 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -14,7 +14,10 @@ export type ExperimentalFeatures = { [K in keyof typeof allowedExperimentalValue export const allowedExperimentalValues = Object.freeze({ tGridEnabled: true, tGridEventRenderedViewEnabled: true, + + // FIXME:PT delete? excludePoliciesInFilterEnabled: false, + kubernetesEnabled: true, chartEmbeddablesEnabled: true, donutChartEmbeddablesEnabled: false, // Depends on https://github.com/elastic/kibana/issues/136409 item 2 - 6 diff --git a/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx b/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx index 0493aadd67211..1bdddde1bdea6 100644 --- a/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx +++ b/x-pack/plugins/security_solution/public/management/components/privileged_route/privileged_route.tsx @@ -21,10 +21,10 @@ export const PrivilegedRoute = memo(({ component, hasPrivilege, path }: Privileg return docLinks.securitySolution.privileges; }, []); - let componentToRender = useMemo(() => { + const componentToRender = useMemo(() => { if (!hasPrivilege) { // eslint-disable-next-line react/display-name - componentToRender = () => ; + return () => ; } return component; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index a8f4e9ab6e408..0d380f71ef7c5 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -32106,8 +32106,6 @@ "xpack.securitySolution.endpointDetails.activityLog.logEntry.response.unisolationSuccessful": "Requête de libération de l'hôte reçue par Endpoint", "xpack.securitySolution.endpointDetails.overview": "Aperçu", "xpack.securitySolution.endpointDetails.responseActionsHistory": "Historique des actions de réponse", - "xpack.securitySolution.endpointManagement.noPermissionsSubText": "Vous devez disposer du rôle de superutilisateur pour utiliser cette fonctionnalité. Si vous ne disposez pas de ce rôle, ni d'autorisations pour modifier les rôles d'utilisateur, contactez votre administrateur Kibana.", - "xpack.securitySolution.endpointManagemnet.noPermissionsText": "Vous ne disposez pas des autorisations Kibana requises pour utiliser Elastic Security Administration", "xpack.securitySolution.endpointPolicyStatus.tooltipTitleLabel": "Politique appliquée", "xpack.securitySolution.endpointResponseActions.actionSubmitter.apiErrorDetails": "L'erreur suivante a été rencontrée :", "xpack.securitySolution.endpointResponseActions.executeAction.successTitle": "L'exécution de la commande a réussi.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7b85916da1808..2522d8f566fd0 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -32087,8 +32087,6 @@ "xpack.securitySolution.endpointDetails.activityLog.logEntry.response.unisolationSuccessful": "エンドポイントが受信したホストリリースリクエスト", "xpack.securitySolution.endpointDetails.overview": "概要", "xpack.securitySolution.endpointDetails.responseActionsHistory": "対応アクション履歴", - "xpack.securitySolution.endpointManagement.noPermissionsSubText": "この機能を使用するには、スーパーユーザーロールが必要です。スーパーユーザーロールがなく、ユーザーロールを編集する権限もない場合は、Kibana管理者に問い合わせてください。", - "xpack.securitySolution.endpointManagemnet.noPermissionsText": "Elastic Security Administrationを使用するために必要なKibana権限がありません。", "xpack.securitySolution.endpointPolicyStatus.tooltipTitleLabel": "ポリシーが適用されました", "xpack.securitySolution.endpointResponseActions.actionSubmitter.apiErrorDetails": "次のエラーが発生しました:", "xpack.securitySolution.endpointResponseActions.executeAction.successTitle": "コマンド実行が成功しました。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 497a4096162b2..6bd5ae297b99f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -32083,8 +32083,6 @@ "xpack.securitySolution.endpointDetails.activityLog.logEntry.response.unisolationSuccessful": "终端收到释放主机请求", "xpack.securitySolution.endpointDetails.overview": "概览", "xpack.securitySolution.endpointDetails.responseActionsHistory": "响应操作历史记录", - "xpack.securitySolution.endpointManagement.noPermissionsSubText": "您必须具有超级用户角色才能使用此功能。如果您不具有超级用户角色,且无权编辑用户角色,请与 Kibana 管理员联系。", - "xpack.securitySolution.endpointManagemnet.noPermissionsText": "您没有所需的 Kibana 权限,无法使用 Elastic Security 管理", "xpack.securitySolution.endpointPolicyStatus.tooltipTitleLabel": "已应用策略", "xpack.securitySolution.endpointResponseActions.actionSubmitter.apiErrorDetails": "遇到以下错误:", "xpack.securitySolution.endpointResponseActions.executeAction.successTitle": "命令执行成功。",