diff --git a/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts b/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts index 21d3584b9fc46..4ef3e263df01c 100644 --- a/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts @@ -34,10 +34,9 @@ describe('Alert Event Details', () => { runKbnArchiverScript(ArchiverMethod.UNLOAD, 'rule'); }); - it('should be able to run live query', () => { + it('should prepare packs and alert rules', () => { const PACK_NAME = 'testpack'; const RULE_NAME = 'Test-rule'; - const TIMELINE_NAME = 'Untitled timeline'; navigateTo('/app/osquery/packs'); preparePack(PACK_NAME); findAndClickButton('Edit'); @@ -57,8 +56,14 @@ describe('Alert Event Details', () => { cy.getBySel('ruleSwitch').should('have.attr', 'aria-checked', 'false'); cy.getBySel('ruleSwitch').click(); cy.getBySel('ruleSwitch').should('have.attr', 'aria-checked', 'true'); + }); + + it('should be able to run live query and add to timeline (-depending on the previous test)', () => { + const TIMELINE_NAME = 'Untitled timeline'; cy.visit('/app/security/alerts'); - cy.wait(500); + cy.getBySel('header-page-title').contains('Alerts').should('exist'); + cy.getBySel('timeline-context-menu-button').first().click({ force: true }); + cy.getBySel('osquery-action-item').should('exist').contains('Run Osquery'); cy.getBySel('expand-event').first().click(); cy.getBySel('take-action-dropdown-btn').click(); cy.getBySel('osquery-action-item').click(); diff --git a/x-pack/plugins/security_solution/common/ecs/agent/index.ts b/x-pack/plugins/security_solution/common/ecs/agent/index.ts index 2332b60f1a3ca..7084214a9b876 100644 --- a/x-pack/plugins/security_solution/common/ecs/agent/index.ts +++ b/x-pack/plugins/security_solution/common/ecs/agent/index.ts @@ -7,4 +7,5 @@ export interface AgentEcs { type?: string[]; + id?: string[]; } diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index 05a91f094ed38..efc4666b7bd61 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -13,6 +13,8 @@ import { connect, ConnectedProps } from 'react-redux'; import { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; import { get } from 'lodash/fp'; import { DEFAULT_ACTION_BUTTON_WIDTH } from '@kbn/timelines-plugin/public'; +import { useOsqueryContextActionItem } from '../../osquery/use_osquery_context_action_item'; +import { OsqueryFlyout } from '../../osquery/osquery_flyout'; import { useRouteSpy } from '../../../../common/utils/route/use_route_spy'; import { buildGetAlertByIdQuery } from '../../../../common/components/exceptions/helpers'; import { useUserPrivileges } from '../../../../common/components/user_privileges'; @@ -63,6 +65,7 @@ const AlertContextMenuComponent: React.FC { const [isPopoverOpen, setPopover] = useState(false); + const [isOsqueryFlyoutOpen, setOsqueryFlyoutOpen] = useState(false); const [routeProps] = useRouteSpy(); const onMenuItemClick = useCallback(() => { @@ -186,18 +189,38 @@ const AlertContextMenuComponent: React.FC get(0, ecsRowData?.agent?.id), [ecsRowData]); + + const handleOnOsqueryClick = useCallback(() => { + setOsqueryFlyoutOpen((prevValue) => !prevValue); + setPopover(false); + }, []); + + const { osqueryActionItems } = useOsqueryContextActionItem({ handleClick: handleOnOsqueryClick }); + const items: React.ReactElement[] = useMemo( () => !isEvent && ruleId - ? [...addToCaseActionItems, ...statusActionItems, ...exceptionActionItems] - : [...addToCaseActionItems, ...eventFilterActionItems], + ? [ + ...addToCaseActionItems, + ...statusActionItems, + ...exceptionActionItems, + ...(agentId ? osqueryActionItems : []), + ] + : [ + ...addToCaseActionItems, + ...eventFilterActionItems, + ...(agentId ? osqueryActionItems : []), + ], [ - statusActionItems, - addToCaseActionItems, - eventFilterActionItems, - exceptionActionItems, isEvent, ruleId, + addToCaseActionItems, + statusActionItems, + exceptionActionItems, + agentId, + osqueryActionItems, + eventFilterActionItems, ] ); @@ -239,6 +262,9 @@ const AlertContextMenuComponent: React.FC )} + {isOsqueryFlyoutOpen && agentId && ecsRowData != null && ( + + )} ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_action_item.tsx b/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_action_item.tsx index ca61e2f3ebf6d..e27a13ef217e3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_action_item.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_action_item.tsx @@ -13,14 +13,12 @@ interface IProps { handleClick: () => void; } -export const OsqueryActionItem = ({ handleClick }: IProps) => { - return ( - - {ACTION_OSQUERY} - - ); -}; +export const OsqueryActionItem = ({ handleClick }: IProps) => ( + + {ACTION_OSQUERY} + +); diff --git a/x-pack/plugins/security_solution/public/detections/components/osquery/use_osquery_context_action_item.tsx b/x-pack/plugins/security_solution/public/detections/components/osquery/use_osquery_context_action_item.tsx new file mode 100644 index 0000000000000..41a78eb32619f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/osquery/use_osquery_context_action_item.tsx @@ -0,0 +1,27 @@ +/* + * 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, { useMemo } from 'react'; +import { OsqueryActionItem } from './osquery_action_item'; +import { useKibana } from '../../../common/lib/kibana'; + +interface IProps { + handleClick: () => void; +} + +export const useOsqueryContextActionItem = ({ handleClick }: IProps) => { + const osqueryActionItem = useMemo( + () => , + [handleClick] + ); + const permissions = useKibana().services.application.capabilities.osquery; + + return { + osqueryActionItems: + permissions?.writeLiveQueries || permissions?.runSavedQueries ? [osqueryActionItem] : [], + }; +}; diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts index 5c6a0ac0bd416..10a4fae0a036d 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts @@ -208,6 +208,9 @@ describe('Search Strategy EQL helper', () => { "_id": "qhymg3cBX5UUcOOYP3Ec", "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005", "agent": Object { + "id": Array [ + "1d15cf9e-3dc7-5b97-f586-743f7c2518b2", + ], "type": Array [ "endpoint", ], @@ -335,6 +338,9 @@ describe('Search Strategy EQL helper', () => { "_id": "qxymg3cBX5UUcOOYP3Ec", "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005", "agent": Object { + "id": Array [ + "1d15cf9e-3dc7-5b97-f586-743f7c2518b2", + ], "type": Array [ "endpoint", ], @@ -476,6 +482,9 @@ describe('Search Strategy EQL helper', () => { "_id": "rBymg3cBX5UUcOOYP3Ec", "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005", "agent": Object { + "id": Array [ + "1d15cf9e-3dc7-5b97-f586-743f7c2518b2", + ], "type": Array [ "endpoint", ], @@ -592,6 +601,9 @@ describe('Search Strategy EQL helper', () => { "_id": "pxymg3cBX5UUcOOYP3Ec", "_index": ".ds-logs-endpoint.events.process-default-2021.02.02-000005", "agent": Object { + "id": Array [ + "1d15cf9e-3dc7-5b97-f586-743f7c2518b2", + ], "type": Array [ "endpoint", ], diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts index 211edec96b8ac..068b52b8cd821 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts @@ -94,6 +94,7 @@ export const TIMELINE_EVENTS_FIELDS = [ 'event.timezone', 'event.type', 'agent.type', + 'agent.id', 'auditd.result', 'auditd.session', 'auditd.data.acct',