Skip to content

Commit

Permalink
[Osquery] Fix small issues in alerts (#128676)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomsonpl authored Apr 4, 2022
1 parent fa74030 commit 5d9aaeb
Show file tree
Hide file tree
Showing 21 changed files with 196 additions and 89 deletions.
9 changes: 9 additions & 0 deletions x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import { preparePack } from '../../tasks/packs';
import { closeModalIfVisible } from '../../tasks/integrations';
import { navigateTo } from '../../tasks/navigation';
import { RESULTS_TABLE, RESULTS_TABLE_BUTTON } from '../../screens/live_query';

describe('Alert Event Details', () => {
before(() => {
Expand Down Expand Up @@ -58,8 +59,16 @@ describe('Alert Event Details', () => {
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('osquery-action-item').click();
cy.contains('1 agent selected.');
inputQuery('select * from uptime;');
submitQuery();
checkResults();

cy.getBySel(RESULTS_TABLE).within(() => {
cy.getBySel(RESULTS_TABLE_BUTTON).should('not.exist');
});
cy.contains('Save for later').click();
cy.contains('Save query');
cy.contains(/^Save$/);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import {
typeInECSFieldInput,
typeInOsqueryFieldInput,
} from '../../tasks/live_query';
import { RESULTS_TABLE_CELL_WRRAPER } from '../../screens/live_query';
import {
RESULTS_TABLE,
RESULTS_TABLE_BUTTON,
RESULTS_TABLE_CELL_WRRAPER,
} from '../../screens/live_query';
import { getAdvancedButton } from '../../screens/integrations';

describe('ALL - Live Query', () => {
Expand Down Expand Up @@ -48,6 +52,9 @@ describe('ALL - Live Query', () => {
submitQuery();

checkResults();
cy.getBySel(RESULTS_TABLE).within(() => {
cy.getBySel(RESULTS_TABLE_BUTTON).should('exist');
});
cy.react(RESULTS_TABLE_CELL_WRRAPER, {
props: { id: 'message', index: 1 },
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ describe('Reader - only READ', () => {
cy.contains('Update query').should('not.exist');
cy.contains(`Delete query`).should('not.exist');
});
it('should not be able to enter live queries with just read and no run saved queries', () => {
navigateTo('/app/osquery/live_queries/new');
cy.waitForReact(1000);
cy.contains('Permission denied');
});
it('should not be able to play in live queries history', () => {
navigateTo('/app/osquery/live_queries');
cy.waitForReact(1000);
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/osquery/cypress/screens/live_query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const ALL_AGENTS_OPTION = '[title="All agents"]';
export const LIVE_QUERY_EDITOR = '#osquery_editor';
export const SUBMIT_BUTTON = '#submit-button';

export const RESULTS_TABLE = 'osqueryResultsTable';
export const RESULTS_TABLE_BUTTON = 'dataGridFullScreenButton';
export const RESULTS_TABLE_CELL_WRRAPER = 'EuiDataGridHeaderCellWrapper';
export const getSavedQueriesDropdown = () =>
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/osquery/cypress/tasks/live_query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const selectAllAgents = () => {
cy.react('EuiComboBox', { props: { placeholder: 'Select agents or groups' } }).type(
'{downArrow}{enter}{esc}'
);
cy.contains('1 agent selected.');
};

export const inputQuery = (query: string) => cy.get(LIVE_QUERY_EDITOR).type(query);
Expand Down
68 changes: 34 additions & 34 deletions x-pack/plugins/osquery/public/agents/agents_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,37 @@ const AgentsTableComponent: React.FC<AgentsTableProps> = ({ agentSelection, onCh
const [numAgentsSelected, setNumAgentsSelected] = useState<number>(0);
const defaultValueInitialized = useRef(false);

const onSelection = useCallback(
(selection: GroupOption[]) => {
// TODO?: optimize this by making the selection computation incremental
const {
newAgentSelection,
selectedAgents,
selectedGroups,
}: {
newAgentSelection: AgentSelection;
selectedAgents: AgentOptionValue[];
selectedGroups: SelectedGroups;
} = generateAgentSelection(selection);
if (newAgentSelection.allAgentsSelected) {
setNumAgentsSelected(totalNumAgents);
} else {
const checkAgent = generateAgentCheck(selectedGroups);
setNumAgentsSelected(
// filter out all the agents counted by selected policies and platforms
selectedAgents.filter(checkAgent).length +
// add the number of agents added via policy and platform groups
getNumAgentsInGrouping(selectedGroups) -
// subtract the number of agents double counted by policy/platform selections
getNumOverlapped(selectedGroups, groups.overlap)
);
}
onChange(newAgentSelection);
setSelectedOptions(selection);
},
[groups, onChange, totalNumAgents]
);

useEffect(() => {
const handleSelectedOptions = (selection: string[], label: string) => {
const agentOptions = find(['label', label], options);
Expand All @@ -95,7 +126,7 @@ const AgentsTableComponent: React.FC<AgentsTableProps> = ({ agentSelection, onCh
});

if (defaultOptions?.length) {
setSelectedOptions(defaultOptions);
onSelection(defaultOptions);
defaultValueInitialized.current = true;
}
}
Expand All @@ -105,7 +136,7 @@ const AgentsTableComponent: React.FC<AgentsTableProps> = ({ agentSelection, onCh
const allAgentsOptions = find(['label', ALL_AGENTS_LABEL], options);

if (allAgentsOptions?.options) {
setSelectedOptions(allAgentsOptions.options);
onSelection(allAgentsOptions.options);
defaultValueInitialized.current = true;
}
}
Expand All @@ -118,7 +149,7 @@ const AgentsTableComponent: React.FC<AgentsTableProps> = ({ agentSelection, onCh
handleSelectedOptions(agentSelection.agents, AGENT_SELECTION_LABEL);
}
}
}, [agentSelection, options, selectedOptions]);
}, [agentSelection, onSelection, options, selectedOptions]);

useEffect(() => {
if (agentsFetched && groupsFetched) {
Expand All @@ -142,37 +173,6 @@ const AgentsTableComponent: React.FC<AgentsTableProps> = ({ agentSelection, onCh
grouper,
]);

const onSelection = useCallback(
(selection: GroupOption[]) => {
// TODO?: optimize this by making the selection computation incremental
const {
newAgentSelection,
selectedAgents,
selectedGroups,
}: {
newAgentSelection: AgentSelection;
selectedAgents: AgentOptionValue[];
selectedGroups: SelectedGroups;
} = generateAgentSelection(selection);
if (newAgentSelection.allAgentsSelected) {
setNumAgentsSelected(totalNumAgents);
} else {
const checkAgent = generateAgentCheck(selectedGroups);
setNumAgentsSelected(
// filter out all the agents counted by selected policies and platforms
selectedAgents.filter(checkAgent).length +
// add the number of agents added via policy and platform groups
getNumAgentsInGrouping(selectedGroups) -
// subtract the number of agents double counted by policy/platform selections
getNumOverlapped(selectedGroups, groups.overlap)
);
}
onChange(newAgentSelection);
setSelectedOptions(selection);
},
[groups, onChange, totalNumAgents]
);

const renderOption = useCallback((option, searchVal, contentClassName) => {
const { label, value } = option;
return value?.groupType === AGENT_GROUP_KEY.Agent ? (
Expand Down
7 changes: 6 additions & 1 deletion x-pack/plugins/osquery/public/components/layouts/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const Tabs = styled(EuiTabs)`
`;

export interface HeaderProps {
children?: React.ReactNode;
maxWidth?: number;
leftColumn?: JSX.Element;
rightColumn?: JSX.Element;
Expand All @@ -55,7 +56,8 @@ const HeaderColumns: React.FC<Omit<HeaderProps, 'tabs'>> = memo(

HeaderColumns.displayName = 'HeaderColumns';

export const Header: React.FC<HeaderProps> = ({
const HeaderComponent: React.FC<HeaderProps> = ({
children,
leftColumn,
rightColumn,
rightColumnGrow,
Expand All @@ -71,6 +73,7 @@ export const Header: React.FC<HeaderProps> = ({
rightColumn={rightColumn}
rightColumnGrow={rightColumnGrow}
/>
{children}
<EuiFlexGroup>
{tabs ? (
<EuiFlexItem>
Expand All @@ -92,3 +95,5 @@ export const Header: React.FC<HeaderProps> = ({
</Wrapper>
</Container>
);

export const Header = React.memo(HeaderComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ export interface WithHeaderLayoutProps extends HeaderProps {
restrictHeaderWidth?: number;
'data-test-subj'?: string;
children?: React.ReactNode;
headerChildren?: React.ReactNode;
}

export const WithHeaderLayout: React.FC<WithHeaderLayoutProps> = ({
restrictWidth,
restrictHeaderWidth,
children,
headerChildren,
'data-test-subj': dataTestSubj,
...rest
}) => (
Expand All @@ -30,7 +32,9 @@ export const WithHeaderLayout: React.FC<WithHeaderLayoutProps> = ({
maxWidth={restrictHeaderWidth}
data-test-subj={dataTestSubj ? `${dataTestSubj}_header` : undefined}
{...rest}
/>
>
{headerChildren}
</Header>
<Page
restrictWidth={restrictWidth || 1200}
data-test-subj={dataTestSubj ? `${dataTestSubj}_page` : undefined}
Expand Down
19 changes: 4 additions & 15 deletions x-pack/plugins/osquery/public/components/osquery_icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,14 @@
* 2.0.
*/

import React, { useEffect, useState } from 'react';
import React from 'react';
import { EuiIcon, EuiIconProps } from '@elastic/eui';
import OsqueryLogo from './osquery.svg';

export type OsqueryIconProps = Omit<EuiIconProps, 'type'>;

const OsqueryIconComponent: React.FC<OsqueryIconProps> = (props) => {
const [Icon, setIcon] = useState<React.ReactElement | null>(null);

// FIXME: This is a hack to force the icon to be loaded asynchronously.
useEffect(() => {
const interval = setInterval(() => {
setIcon(<EuiIcon size="xl" type={OsqueryLogo} {...props} />);
}, 0);

return () => clearInterval(interval);
}, [props, setIcon]);

return Icon;
};
const OsqueryIconComponent: React.FC<OsqueryIconProps> = (props) => (
<EuiIcon size="xl" type={OsqueryLogo} {...props} />
);

export const OsqueryIcon = React.memo(OsqueryIconComponent);
17 changes: 12 additions & 5 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;
hideFullscreen?: true;
}

const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
Expand All @@ -72,6 +73,7 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
ecsMappingField = true,
formType = 'steps',
enabled = true,
hideFullscreen,
}) => {
const ecsFieldRef = useRef<ECSMappingEditorFieldRef>();
const permissions = useKibana().services.application.capabilities.osquery;
Expand Down Expand Up @@ -146,7 +148,7 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
onSubmit: async (formData, isValid) => {
const ecsFieldValue = await ecsFieldRef?.current?.validate();

if (isValid) {
if (isValid && !!ecsFieldValue) {
try {
await mutateAsync(
pickBy(
Expand Down Expand Up @@ -268,9 +270,9 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({

const ecsFieldProps = useMemo(
() => ({
isDisabled: !permissions.writeSavedQueries,
isDisabled: !permissions.writeLiveQueries,
}),
[permissions.writeSavedQueries]
[permissions.writeLiveQueries]
);

const isSavedQueryDisabled = useMemo(
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}
hideFullscreen={hideFullscreen}
/>
) : null,
[actionId, agentIds, data?.actions]
[actionId, agentIds, data?.actions, hideFullscreen]
);

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';
hideFullscreen?: true;
}

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

Expand Down Expand Up @@ -113,6 +115,7 @@ const LiveQueryComponent: React.FC<LiveQueryProps> = ({
onSuccess={onSuccess}
formType={formType}
enabled={enabled}
hideFullscreen={hideFullscreen}
/>
);
};
Expand Down
8 changes: 6 additions & 2 deletions x-pack/plugins/osquery/public/packs/form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@ const CommonUseField = getUseField({ component: Field });
interface PackFormProps {
defaultValue?: OsqueryManagerPackagePolicy;
editMode?: boolean;
isReadOnly?: boolean;
}

const PackFormComponent: React.FC<PackFormProps> = ({ defaultValue, editMode = false }) => {
const isReadOnly = !!defaultValue?.read_only;
const PackFormComponent: React.FC<PackFormProps> = ({
defaultValue,
editMode = false,
isReadOnly = false,
}) => {
const [showConfirmationModal, setShowConfirmationModal] = useState(false);
const handleHideConfirmationModal = useCallback(() => setShowConfirmationModal(false), []);

Expand Down
Loading

0 comments on commit 5d9aaeb

Please sign in to comment.