Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Osquery] Add to timeline button #128596

Merged
merged 30 commits into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9a0ea9f
[wip]
tomsonpl Mar 28, 2022
ef1bcd4
fix timeline rerender and change action_id
tomsonpl Mar 28, 2022
635af17
Merge branch 'main' into osquery-add-to-timeline
kibanamachine Mar 28, 2022
e483a17
fix zindex issue
tomsonpl Mar 28, 2022
2d4b13b
Merge branch 'osquery-add-to-timeline' of github.com:tomsonpl/kibana …
tomsonpl Mar 28, 2022
0b3d977
fix eslint
tomsonpl Mar 28, 2022
b06a58f
add timeline e2e test to alerts
tomsonpl Mar 29, 2022
9b33c21
Merge branch 'main' into osquery-add-to-timeline
kibanamachine Mar 29, 2022
2bdb838
Merge branch 'main' into osquery-add-to-timeline
kibanamachine Mar 31, 2022
d7cccf6
Merge branch 'main' into osquery-add-to-timeline
kibanamachine Apr 4, 2022
2650b51
Add timeline to row (by _id)
tomsonpl Apr 6, 2022
24649a5
Merge branch 'main' into osquery-add-to-timeline
tomsonpl Apr 25, 2022
1e86af8
Resolev conflicts - remove hideFullscreen
tomsonpl Apr 25, 2022
99bdaeb
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Apr 25, 2022
cb087ec
fix tests
tomsonpl Apr 25, 2022
1a00d81
Merge remote-tracking branch 'origin/osquery-add-to-timeline' into os…
tomsonpl Apr 25, 2022
b77290c
fix tests
tomsonpl Apr 25, 2022
5caef62
Merge branch 'main' into osquery-add-to-timeline
tomsonpl Apr 25, 2022
afc5980
Merge branch 'main' into osquery-add-to-timeline
tomsonpl Apr 26, 2022
3c66905
refactor payload destructuring
tomsonpl Apr 28, 2022
bcf8613
Merge branch 'main' into osquery-add-to-timeline
tomsonpl Apr 28, 2022
0742331
fix after merge
tomsonpl Apr 28, 2022
dbe1048
fix tests
tomsonpl Apr 28, 2022
faaaced
Merge branch 'main' into osquery-add-to-timeline
kibanamachine Apr 28, 2022
6717b51
Merge branch 'main' into osquery-add-to-timeline
kibanamachine Apr 28, 2022
7cbda37
remove go back button from osquery flyout
tomsonpl Apr 28, 2022
81ebe56
Merge remote-tracking branch 'origin/osquery-add-to-timeline' into os…
tomsonpl Apr 28, 2022
8cead6b
Merge branch 'main' into osquery-add-to-timeline
kibanamachine Apr 28, 2022
ad9c19c
fix tests
tomsonpl Apr 28, 2022
dae6719
Merge remote-tracking branch 'origin/osquery-add-to-timeline' into os…
tomsonpl Apr 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe('Alert Event Details', () => {
it('should be able to run live query', () => {
const PACK_NAME = 'testpack';
const RULE_NAME = 'Test-rule';
const TIMELINE_NAME = 'Untitled timeline';
navigateTo('/app/osquery/packs');
preparePack(PACK_NAME);
findAndClickButton('Edit');
Expand All @@ -61,5 +62,10 @@ describe('Alert Event Details', () => {
inputQuery('select * from uptime;');
submitQuery();
checkResults();
cy.getBySel('add-to-timeline').click();
cy.getBySel('globalToastList').contains('Added');
cy.contains('Cancel').click();
cy.contains(TIMELINE_NAME).click();
cy.getBySel('draggableWrapperKeyboardHandler').contains('action_id: "');
});
});
11 changes: 9 additions & 2 deletions x-pack/plugins/osquery/public/live_queries/form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ interface LiveQueryFormProps {
ecsMappingField?: boolean;
formType?: FormType;
enabled?: boolean;
addToTimeline?: (actionId: string) => void;
}

const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
Expand All @@ -72,6 +73,7 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
ecsMappingField = true,
formType = 'steps',
enabled = true,
addToTimeline,
}) => {
const ecsFieldRef = useRef<ECSMappingEditorFieldRef>();
const permissions = useKibana().services.application.capabilities.osquery;
Expand Down Expand Up @@ -388,9 +390,14 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
const resultsStepContent = useMemo(
() =>
actionId ? (
<ResultTabs actionId={actionId} endDate={data?.actions[0].expiration} agentIds={agentIds} />
<ResultTabs
actionId={actionId}
endDate={data?.actions[0].expiration}
agentIds={agentIds}
addToTimeline={addToTimeline}
/>
) : null,
[actionId, agentIds, data?.actions]
[actionId, agentIds, data?.actions, addToTimeline]
);

const formSteps: EuiContainedStepProps[] = useMemo(
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/osquery/public/live_queries/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface LiveQueryProps {
ecsMappingField?: boolean;
enabled?: boolean;
formType?: 'steps' | 'simple';
addToTimeline?: (actionId: string) => void;
}

const LiveQueryComponent: React.FC<LiveQueryProps> = ({
Expand All @@ -44,6 +45,7 @@ const LiveQueryComponent: React.FC<LiveQueryProps> = ({
ecsMappingField,
formType,
enabled,
addToTimeline,
}) => {
const { data: hasActionResultsPrivileges, isLoading } = useActionResultsPrivileges();

Expand Down Expand Up @@ -113,6 +115,7 @@ const LiveQueryComponent: React.FC<LiveQueryProps> = ({
onSuccess={onSuccess}
formType={formType}
enabled={enabled}
addToTimeline={addToTimeline}
/>
);
};
Expand Down
6 changes: 5 additions & 1 deletion x-pack/plugins/osquery/public/results/results_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ interface ResultsTableComponentProps {
agentIds?: string[];
endDate?: string;
startDate?: string;
addToTimeline?: (actionId: string) => void;
}

const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
actionId,
agentIds,
startDate,
endDate,
addToTimeline,
}) => {
const [isLive, setIsLive] = useState(true);
const { data: hasActionResultsPrivileges } = useActionResultsPrivileges();
Expand Down Expand Up @@ -307,6 +309,7 @@ const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
const toolbarVisibility = useMemo(
() => ({
showDisplaySelector: false,
showFullScreenSelector: !addToTimeline,
additionalControls: (
<>
<ViewResultsInDiscoverAction
Expand All @@ -321,10 +324,11 @@ const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
endDate={endDate}
startDate={startDate}
/>
{addToTimeline && addToTimeline(actionId)}
</>
),
}),
[actionId, endDate, startDate]
[actionId, addToTimeline, endDate, startDate]
);

useEffect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ interface ResultTabsProps {
agentIds?: string[];
startDate?: string;
endDate?: string;
addToTimeline?: (actionId: string) => void;
}

const ResultTabsComponent: React.FC<ResultTabsProps> = ({
actionId,
agentIds,
endDate,
startDate,
addToTimeline,
}) => {
const tabs = useMemo(
() => [
Expand All @@ -38,6 +40,7 @@ const ResultTabsComponent: React.FC<ResultTabsProps> = ({
agentIds={agentIds}
startDate={startDate}
endDate={endDate}
addToTimeline={addToTimeline}
/>
</>
),
Expand All @@ -57,7 +60,7 @@ const ResultTabsComponent: React.FC<ResultTabsProps> = ({
),
},
],
[actionId, agentIds, endDate, startDate]
[actionId, agentIds, endDate, startDate, addToTimeline]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ const SavedQueryFlyoutComponent: React.FC<AddQueryFlyoutProps> = ({ defaultValue

return (
<EuiPortal>
<EuiFlyout size="m" ownFocus onClose={onClose} aria-labelledby="flyoutTitle">
<EuiFlyout
size="m"
ownFocus
onClose={onClose}
aria-labelledby="flyoutTitle"
// eslint-disable-next-line react-perf/jsx-no-new-object-as-prop
maskProps={{ style: 'z-index: 6000' }} // For an edge case to display above the alerts flyout
Copy link
Contributor

@kqualters-elastic kqualters-elastic Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I see below that this flyout has a form in it, did you verify that all the select dropdowns etc that render in this form, namely EuiSuperSelect options and anything that renders itself via a portal (not sure of everything) render correctly? I noticed recently that any element that renders itself in a portal and has a parent that is also in a portal, when it tries to determine it's own stacking context cannot have a z-index higher than 2000 or something. https://codesandbox.io/s/crimson-voice-zq510u?file=/demo.js for a demo. Mentioned this to eui but they didn't seem to think it's a bug, personally I do, https://github.com/elastic/eui/blob/main/src/services/popover/popover_positioning.ts#L743 for an element in a portal will not do what it should.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I don't know yet, but will take a look at this and get back to you. Big thanks! :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I double checked and it seems to be working just fine. Selects too :)
The only thing is the Global NavBar that doesnt really work when any of the additional flyouts is opened.

Copy link
Contributor Author

@tomsonpl tomsonpl Apr 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we checked one more time, and apparently it works fine on Alerts, but messes up one of the flyouts in Osquery itself.

Thanks for pointing this out :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the issue is fixed here #130944

>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="s">
<h2 id="flyoutTitle">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ import { useIsOsqueryAvailable } from './use_is_osquery_available';
interface OsqueryActionProps {
agentId?: string;
formType: 'steps' | 'simple';
addToTimeline: (actionId: string) => void;
}

const OsqueryActionComponent: React.FC<OsqueryActionProps> = ({ agentId, formType = 'simple' }) => {
const OsqueryActionComponent: React.FC<OsqueryActionProps> = ({
agentId,
formType = 'simple',
addToTimeline,
}) => {
const permissions = useKibana().services.application.capabilities.osquery;

const emptyPrompt = useMemo(
Expand Down Expand Up @@ -134,18 +139,18 @@ const OsqueryActionComponent: React.FC<OsqueryActionProps> = ({ agentId, formTyp
);
}

return <LiveQuery formType={formType} agentId={agentId} />;
return <LiveQuery formType={formType} agentId={agentId} addToTimeline={addToTimeline} />;
};

const OsqueryAction = React.memo(OsqueryActionComponent);

// @ts-expect-error update types
const OsqueryActionWrapperComponent = ({ services, agentId, formType }) => (
const OsqueryActionWrapperComponent = ({ services, agentId, formType, addToTimeline }) => (
<KibanaThemeProvider theme$={services.theme.theme$}>
<KibanaContextProvider services={services}>
<EuiErrorBoundary>
<QueryClientProvider client={queryClient}>
<OsqueryAction agentId={agentId} formType={formType} />
<OsqueryAction agentId={agentId} formType={formType} addToTimeline={addToTimeline} />
</QueryClientProvider>
</EuiErrorBoundary>
</KibanaContextProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@
* 2.0.
*/

import React from 'react';
import React, { useCallback } from 'react';
import styled from 'styled-components';
import { EuiFlyout, EuiFlyoutFooter, EuiFlyoutBody, EuiFlyoutHeader } from '@elastic/eui';
import {
EuiFlyout,
EuiFlyoutFooter,
EuiFlyoutBody,
EuiFlyoutHeader,
EuiButtonEmpty,
} from '@elastic/eui';
import { useKibana } from '../../../common/lib/kibana';
import { OsqueryEventDetailsFooter } from './osquery_flyout_footer';
import { OsqueryEventDetailsHeader } from './osquery_flyout_header';
import { ACTION_OSQUERY } from './translations';
import { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider';

const OsqueryActionWrapper = styled.div`
padding: 8px;
Expand All @@ -22,11 +29,43 @@ export interface OsqueryFlyoutProps {
onClose: () => void;
}

export const OsqueryFlyout: React.FC<OsqueryFlyoutProps> = ({ agentId, onClose }) => {
const TimelineComponent = React.memo((props) => {
return <EuiButtonEmpty {...props} size="xs" />;
});
TimelineComponent.displayName = 'TimelineComponent';

export const OsqueryFlyoutComponent: React.FC<OsqueryFlyoutProps> = ({ agentId, onClose }) => {
const {
services: { osquery },
services: { osquery, timelines },
} = useKibana();

const { getAddToTimelineButton } = timelines.getHoverActions();

const handleAddToTimeline = useCallback(
(actionId: string) => {
const providerA: DataProvider = {
and: [],
enabled: true,
excluded: false,
id: actionId,
kqlQuery: '',
name: actionId,
queryMatch: {
field: 'action_id',
value: actionId,
operator: ':',
},
};

return getAddToTimelineButton({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have at least a unit test to check the flyout is rendered correctly according to the props and then check if add to timeline was executed with the right options.

dataProvider: providerA,
field: actionId,
ownFocus: false,
Component: TimelineComponent,
});
},
[getAddToTimelineButton]
);
// @ts-expect-error
const { OsqueryAction } = osquery;
return (
Expand All @@ -45,7 +84,7 @@ export const OsqueryFlyout: React.FC<OsqueryFlyoutProps> = ({ agentId, onClose }
</EuiFlyoutHeader>
<EuiFlyoutBody>
<OsqueryActionWrapper data-test-subj="flyout-body-osquery">
<OsqueryAction agentId={agentId} formType="steps" />
<OsqueryAction agentId={agentId} formType="steps" addToTimeline={handleAddToTimeline} />
</OsqueryActionWrapper>
</EuiFlyoutBody>
<EuiFlyoutFooter>
Expand All @@ -55,4 +94,4 @@ export const OsqueryFlyout: React.FC<OsqueryFlyoutProps> = ({ agentId, onClose }
);
};

OsqueryFlyout.displayName = 'OsqueryFlyout';
export const OsqueryFlyout = React.memo(OsqueryFlyoutComponent);