Skip to content

Commit

Permalink
[Security Solution] Adds feature flag to enable/disable ESQL in timel…
Browse files Browse the repository at this point in the history
…ine (elastic#174029)

## Summary

This PR introduces a feature flag `timelineEsqlTabDisabled` which is by
default `false`. This gives customer ability to disable the esql tab by
enabling this experimental feature flag as below in `kibana.yml`

```yaml
xpack.securitySolution.enableExperimental:
  - timelineEsqlTabDisabled

```

The availability of ESQL Tab in timeline also affects `AI Assistant` as
it facilities re-directing user to timeline with an esql query. That
`redirect` button should not be available for `esql` query if ESQL Tab
is disabled.

## Desk Testing

1. ESQL Tab Presence
    -  timelineEsqlTabDisabled :  true
- If Tab is disabled, `ESQL` Tab should not show when timeline is open.
Timeline should also not fire any `bsearch` requests with `esql`
strategy.
- ESQL tab is enabled i.e. `timelineEsqlTabDisabled : true` is present
in kibana.dev.yml
- User should be able to use ESQL queries without any issue. Below
should be the default query in both `8.12` and `8.11.4`
       ```esql
from
.alerts-security.alerts-default,apm-*-transaction*,auditbeat-*,endgame-*,filebeat-*,logs-*,packetbeat-*,traces-apm*,winlogbeat-*,-*elastic-cloud-logs-*
| limit 10 | keep @timestamp, message, event.category, event.action,
host.name, source.ip, destination.ip, user.name
       ```
2. Open ESQL Tab from URL
    1. Enable ESQL tab and Activate it when in timeline
2. Now change `kibana.dev.yml` to add experimental flag
`timelineEsqlTabDisabled` to disable ESQL Tab.
    3. Restart kibana server
    4. Refresh the page in step 1 where `ESQL` tab was active
    5. User should automatically be redirected to `Query` tab.

3. AI Assistant
Today AI Assistant can help user add an ESQL query to the timeline as
shown in below video.
We need to make sure that `Send to timeline` button is not available
only for `esql` queries when above experimental flag is enabled.

https://github.com/elastic/kibana/assets/7485038/e452a6c6-cf97-462e-a5dc-bd8c0fd38d58

---------

Co-authored-by: Gloria Hornero <[email protected]>
Co-authored-by: kibanamachine <[email protected]>
(cherry picked from commit da0370e)

# Conflicts:
#	x-pack/plugins/security_solution/common/experimental_features.ts
#	x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx
  • Loading branch information
logeekal committed Jan 2, 2024
1 parent d425e3a commit 1e5c067
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ export const allowedExperimentalValues = Object.freeze({
* Enables Protection Updates tab in the Endpoint Policy Details page
*/
protectionUpdatesEnabled: true,

/*
* Disables discover esql tab within timeline
*
*/
timelineEsqlTabDisabled: false,
});

type ExperimentalConfigKeys = Array<keyof ExperimentalFeatures>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
} from '../../timelines/store/timeline/actions';
import { useDiscoverInTimelineContext } from '../../common/components/discover_in_timeline/use_discover_in_timeline_context';
import { useShowTimeline } from '../../common/utils/timeline/use_show_timeline';
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';

export interface SendToTimelineButtonProps {
asEmptyButton: boolean;
Expand All @@ -60,6 +61,8 @@ export const SendToTimelineButton: React.FunctionComponent<SendToTimelineButtonP
const [isTimelineBottomBarVisible] = useShowTimeline();
const { discoverStateContainer } = useDiscoverInTimelineContext();

const isEsqlTabInTimelineDisabled = useIsExperimentalFeatureEnabled('timelineEsqlTabDisabled');

const getDataViewsSelector = useMemo(
() => sourcererSelectors.getSourcererDataViewsSelector(),
[]
Expand Down Expand Up @@ -226,6 +229,13 @@ export const SendToTimelineButton: React.FunctionComponent<SendToTimelineButtonP
: ACTION_CANNOT_INVESTIGATE_IN_TIMELINE;
const isDisabled = !isTimelineBottomBarVisible;

if (
(dataProviders?.[0]?.queryType === 'esql' || dataProviders?.[0]?.queryType === 'sql') &&
isEsqlTabInTimelineDisabled
) {
return null;
}

return asEmptyButton ? (
<EuiButtonEmpty
aria-label={toolTipText}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useCallback } from 'react';

import { useDispatch } from 'react-redux';

import { TimelineTabs } from '../../../../common/types';
import { useInitializeUrlParam } from '../../utils/global_query_string';
import {
dispatchUpdateTimeline,
Expand All @@ -17,15 +18,21 @@ import {
import type { TimelineUrl } from '../../../timelines/store/timeline/model';
import { timelineActions } from '../../../timelines/store/timeline';
import { URL_PARAM_KEY } from '../use_url_state';
import { useIsExperimentalFeatureEnabled } from '../use_experimental_features';

export const useInitTimelineFromUrlParam = () => {
const dispatch = useDispatch();

const isEsqlTabDisabled = useIsExperimentalFeatureEnabled('timelineEsqlTabDisabled');

const onInitialize = useCallback(
(initialState: TimelineUrl | null) => {
if (initialState != null) {
queryTimelineById({
activeTimelineTab: initialState.activeTab,
activeTimelineTab:
initialState.activeTab === TimelineTabs.esql && isEsqlTabDisabled
? TimelineTabs.query
: initialState.activeTab,
duplicate: false,
graphEventId: initialState.graphEventId,
timelineId: initialState.id,
Expand All @@ -37,7 +44,7 @@ export const useInitTimelineFromUrlParam = () => {
});
}
},
[dispatch]
[dispatch, isEsqlTabDisabled]
);

useInitializeUrlParam(URL_PARAM_KEY.timeline, onInitialize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { useDispatch } from 'react-redux';
import styled from 'styled-components';

import { FormattedMessage } from '@kbn/i18n-react';
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
import { useKibana } from '../../../../common/lib/kibana';
import { useAssistantTelemetry } from '../../../../assistant/use_assistant_telemetry';
import { useConversationStore } from '../../../../assistant/use_conversation_store';
import { useAssistantAvailability } from '../../../../assistant/use_assistant_availability';
Expand Down Expand Up @@ -132,6 +134,7 @@ const ActiveTimelineTab = memo<ActiveTimelineTabProps>(
setConversationId,
showTimeline,
}) => {
const isEsqlSettingEnabled = useKibana().services.configSettings.ESQLEnabled;
const { hasAssistantPrivilege } = useAssistantAvailability();
const getTab = useCallback(
(tab: TimelineTabs) => {
Expand Down Expand Up @@ -179,12 +182,14 @@ const ActiveTimelineTab = memo<ActiveTimelineTabProps>(
timelineId={timelineId}
/>
</HideShowContainer>
<HideShowContainer
$isVisible={TimelineTabs.esql === activeTimelineTab}
data-test-subj={`timeline-tab-content-${TimelineTabs.esql}`}
>
<EsqlTab timelineId={timelineId} />
</HideShowContainer>
{showTimeline && isEsqlSettingEnabled && activeTimelineTab === TimelineTabs.esql && (
<HideShowContainer
$isVisible={true}
data-test-subj={`timeline-tab-content-${TimelineTabs.esql}`}
>
<EsqlTab timelineId={timelineId} />
</HideShowContainer>
)}
<HideShowContainer
$isVisible={TimelineTabs.pinned === activeTimelineTab}
data-test-subj={`timeline-tab-content-${TimelineTabs.pinned}`}
Expand Down Expand Up @@ -281,6 +286,8 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
sessionViewConfig,
timelineDescription,
}) => {
const isEsqlTabInTimelineDisabled = useIsExperimentalFeatureEnabled('timelineEsqlTabDisabled');
const isEsqlSettingEnabled = useKibana().services.configSettings.ESQLEnabled;
const { hasAssistantPrivilege } = useAssistantAvailability();
const dispatch = useDispatch();
const getActiveTab = useMemo(() => getActiveTabSelector(), []);
Expand Down Expand Up @@ -394,26 +401,28 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
<span>{i18n.QUERY_TAB}</span>
{showTimeline && <TimelineEventsCountBadge />}
</StyledEuiTab>
<StyledEuiTab
data-test-subj={`timelineTabs-${TimelineTabs.esql}`}
onClick={setEsqlAsActiveTab}
isSelected={activeTab === TimelineTabs.esql}
disabled={false}
key={TimelineTabs.esql}
>
<span>{i18n.DISCOVER_ESQL_IN_TIMELINE_TAB}</span>
<StyledEuiBetaBadge
label={DISCOVER_ESQL_IN_TIMELINE_TECHNICAL_PREVIEW}
size="s"
iconType="beaker"
tooltipContent={
<FormattedMessage
id="xpack.securitySolution.timeline.tabs.discoverEsqlInTimeline.technicalPreviewTooltip"
defaultMessage="This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features."
/>
}
/>
</StyledEuiTab>
{!isEsqlTabInTimelineDisabled && isEsqlSettingEnabled && (
<StyledEuiTab
data-test-subj={`timelineTabs-${TimelineTabs.esql}`}
onClick={setEsqlAsActiveTab}
isSelected={activeTab === TimelineTabs.esql}
disabled={false}
key={TimelineTabs.esql}
>
<span>{i18n.DISCOVER_ESQL_IN_TIMELINE_TAB}</span>
<StyledEuiBetaBadge
label={DISCOVER_ESQL_IN_TIMELINE_TECHNICAL_PREVIEW}
size="s"
iconType="beaker"
tooltipContent={
<FormattedMessage
id="xpack.securitySolution.timeline.tabs.discoverEsqlInTimeline.technicalPreviewTooltip"
defaultMessage="This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features."
/>
}
/>
</StyledEuiTab>
)}
{timelineType === TimelineType.default && (
<StyledEuiTab
data-test-subj={`timelineTabs-${TimelineTabs.eql}`}
Expand Down

0 comments on commit 1e5c067

Please sign in to comment.