Session view and k8s dashboard fixes (#154982)

## Summary

- fixes some issues in session_view wrt to logs-cloud_defend.process*
data.
- added a 'collapse all' children feature. with sticky scroll session
leader!
- k8s dashboard session table: user.name -> user.id (id is more likely
to be set for both endpoint and cloud-defend)
- Fixed a major bug when 'searching within terminal'. If a process is
highlighted it would cause kibana to blow up.
- session view handling of session leader user info improved.
- codeowners updated. awp-viz -> sec-cloudnative-integrations
- a badge will be added to the selector header when it's not in used by
a response flow

### Screenshots

![image](https://user-images.githubusercontent.com/16198204/232567236-98e57a3a-913c-4a25-8271-e1ee138b25dd.png)

Sticky session leader demo:
https://www.loom.com/share/b039e48fdfd647b291f293d643339660

### Checklist

Delete any items that are not applicable to this PR.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Karl Godard 2023-04-17 16:22:28 -07:00 committed by GitHub
parent 28b1f96d47
commit 0a5b4233d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 162 additions and 90 deletions

8
.github/CODEOWNERS vendored
View file

@ -431,7 +431,7 @@ src/plugins/kibana_overview @elastic/appex-sharedux
src/plugins/kibana_react @elastic/appex-sharedux
src/plugins/kibana_usage_collection @elastic/kibana-core
src/plugins/kibana_utils @elastic/kibana-app-services
x-pack/plugins/kubernetes_security @elastic/awp-viz
x-pack/plugins/kubernetes_security @elastic/sec-cloudnative-integrations
packages/kbn-language-documentation-popover @elastic/kibana-visualizations
x-pack/plugins/lens @elastic/kibana-visualizations
x-pack/plugins/license_api_guard @elastic/platform-deployment-management
@ -567,7 +567,7 @@ packages/kbn-securitysolution-utils @elastic/security-solution-platform
packages/kbn-server-http-tools @elastic/kibana-core
packages/kbn-server-route-repository @elastic/apm-ui
test/plugin_functional/plugins/session_notifications @elastic/kibana-core
x-pack/plugins/session_view @elastic/awp-viz
x-pack/plugins/session_view @elastic/sec-cloudnative-integrations
packages/kbn-set-map @elastic/kibana-operations
examples/share_examples @elastic/kibana-app-services
src/plugins/share @elastic/appex-sharedux
@ -1176,8 +1176,8 @@ x-pack/plugins/security_solution/cypress/README.md @elastic/security-engineering
x-pack/test/security_solution_cypress @elastic/security-engineering-productivity
## Security Solution sub teams - adaptive-workload-protection
x-pack/plugins/security_solution/public/common/components/sessions_viewer @elastic/awp-viz
x-pack/plugins/security_solution/public/kubernetes @elastic/awp-viz
x-pack/plugins/security_solution/public/common/components/sessions_viewer @elastic/sec-cloudnative-integrations
x-pack/plugins/security_solution/public/kubernetes @elastic/sec-cloudnative-integrations
## Security Solution sub teams - Protections Experience
x-pack/plugins/security_solution/public/threat_intelligence @elastic/protections-experience

View file

@ -15,7 +15,7 @@ import kubernetesSecurityObj from './kubernetes_security.devdocs.json';
Contact [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) for questions regarding this plugin.
Contact [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) for questions regarding this plugin.
**Code health stats**

View file

@ -113,7 +113,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana']
| <DocLink id="kibKibanaReactPluginApi" text="kibanaReact"/> | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 185 | 1 | 153 | 5 |
| kibanaUsageCollection | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 |
| <DocLink id="kibKibanaUtilsPluginApi" text="kibanaUtils"/> | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 609 | 3 | 416 | 9 |
| <DocLink id="kibKubernetesSecurityPluginApi" text="kubernetesSecurity"/> | [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) | - | 3 | 0 | 3 | 1 |
| <DocLink id="kibKubernetesSecurityPluginApi" text="kubernetesSecurity"/> | [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) | - | 3 | 0 | 3 | 1 |
| <DocLink id="kibLensPluginApi" text="lens"/> | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 608 | 0 | 513 | 53 |
| <DocLink id="kibLicenseApiGuardPluginApi" text="licenseApiGuard"/> | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 8 | 0 | 8 | 0 |
| <DocLink id="kibLicenseManagementPluginApi" text="licenseManagement"/> | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 1 |
@ -151,7 +151,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana']
| searchprofiler | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 |
| <DocLink id="kibSecurityPluginApi" text="security"/> | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 280 | 0 | 94 | 0 |
| <DocLink id="kibSecuritySolutionPluginApi" text="securitySolution"/> | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 117 | 0 | 76 | 27 |
| <DocLink id="kibSessionViewPluginApi" text="sessionView"/> | [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) | - | 7 | 0 | 7 | 1 |
| <DocLink id="kibSessionViewPluginApi" text="sessionView"/> | [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) | - | 7 | 0 | 7 | 1 |
| <DocLink id="kibSharePluginApi" text="share"/> | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds URL Service and sharing capabilities to Kibana | 118 | 0 | 59 | 10 |
| <DocLink id="kibSnapshotRestorePluginApi" text="snapshotRestore"/> | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 22 | 1 | 22 | 1 |
| <DocLink id="kibSpacesPluginApi" text="spaces"/> | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 253 | 0 | 65 | 0 |

View file

@ -15,7 +15,7 @@ import sessionViewObj from './session_view.devdocs.json';
Contact [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) for questions regarding this plugin.
Contact [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) for questions regarding this plugin.
**Code health stats**

View file

@ -270,7 +270,7 @@
{
"groupName": "TTY Output",
"matchPackageNames": ["xterm", "byte-size", "@types/byte-size"],
"reviewers": ["team:awp-viz"],
"reviewers": ["team:sec-cloudnative-integrations"],
"matchBaseBranches": ["main"],
"labels": ["Team: AWP: Visualization", "release_note:skip", "backport:skip"],
"enabled": true,

View file

@ -54,7 +54,7 @@ describe('getSelectorConditions', () => {
// check that process specific conditions are not included
expect(options.includes('processExecutable')).toBeFalsy();
expect(options.includes('processUserId')).toBeFalsy();
expect(options.includes('sessionLeaderInteractive')).toBeFalsy();
});
it('grabs process conditions for process selectors', () => {
@ -70,7 +70,6 @@ describe('getSelectorConditions', () => {
// check that process specific conditions are not included
expect(options.includes('processExecutable')).toBeTruthy();
expect(options.includes('processUserId')).toBeTruthy();
expect(options.includes('sessionLeaderInteractive')).toBeTruthy();
});
});

View file

@ -338,6 +338,10 @@ export const ControlGeneralView = ({ policy, onChange, show }: ViewDeps) => {
</EuiFlexItem>
{selectors.map((selector, i) => {
const usedByResponse = !!responses.find((response) =>
response.match.includes(selector.name)
);
return (
<EuiFlexItem key={i}>
<ControlGeneralViewSelector
@ -345,6 +349,7 @@ export const ControlGeneralView = ({ policy, onChange, show }: ViewDeps) => {
index={i}
selector={selector}
selectors={selectors}
usedByResponse={usedByResponse}
onDuplicate={onDuplicateSelector}
onRemove={onRemoveSelector}
onChange={onSelectorChange}

View file

@ -116,6 +116,14 @@ export const name = i18n.translate('xpack.cloudDefend.name', {
defaultMessage: 'Name',
});
export const unusedSelector = i18n.translate('xpack.cloudDefend.unusedSelector', {
defaultMessage: 'Not in use',
});
export const unusedSelectorHelp = i18n.translate('xpack.cloudDefend.unusedSelectorHelp', {
defaultMessage: 'This selector is not in use by any response.',
});
export const errorInvalidResourceLabel = i18n.translate(
'xpack.cloudDefend.errorInvalidResourceLabel',
{

View file

@ -50,6 +50,7 @@ describe('<ControlGeneralViewSelector />', () => {
onChange={onChange}
onRemove={onRemove}
onDuplicate={onDuplicate}
usedByResponse={false}
/>
</TestProvider>
);
@ -68,6 +69,12 @@ describe('<ControlGeneralViewSelector />', () => {
expect(getByTestId('cloud-defend-selectorcondition-operation')).toBeTruthy();
});
it('renders a badge to show that the selector is unused', () => {
const { getByText } = render(<WrappedComponent />);
expect(getByText(i18n.unusedSelector)).toBeTruthy();
});
it('allows the user to add a limited set of operations', () => {
const { getByTestId, rerender } = render(<WrappedComponent />);

View file

@ -184,6 +184,7 @@ const StringArrayCondition = ({
export const ControlGeneralViewSelector = ({
selector,
selectors,
usedByResponse,
index,
onRemove,
onDuplicate,
@ -393,17 +394,24 @@ export const ControlGeneralViewSelector = ({
css={styles.accordion}
extraAction={
<EuiFlexGroup alignItems="center" gutterSize="none">
{accordionState === 'closed' && (
<div>
<EuiText css={styles.conditionsBadge} size="xs">
<b>{i18n.conditions}</b>
</EuiText>
<EuiBadge title={conditionsAdded.join(',')} color="hollow">
{conditionsAdded.length}
<div>
{accordionState === 'closed' && (
<>
<EuiText css={styles.conditionsBadge} size="xs">
<b>{i18n.conditions}</b>
</EuiText>
<EuiBadge title={conditionsAdded.join(',')} color="hollow">
{conditionsAdded.length}
</EuiBadge>
</>
)}
{!usedByResponse && (
<EuiBadge title={i18n.unusedSelectorHelp} color="warning">
{i18n.unusedSelector}
</EuiBadge>
<div css={styles.verticalDivider} />
</div>
)}
)}
<div css={styles.verticalDivider} />
</div>
<EuiFlexItem>
<EuiPopover
id={selector.name}

View file

@ -240,14 +240,8 @@
{
"required": ["processName"]
},
{
"required": ["processUserId"]
},
{
"required": ["sessionLeaderInteractive"]
},
{
"required": ["sessionLeaderName"]
}
],
"properties": {
@ -335,22 +329,8 @@
"type": "string"
}
},
"processUserId": {
"type": "array",
"minItems": 1,
"items": {
"type": "integer"
}
},
"sessionLeaderInteractive": {
"type": "boolean"
},
"sessionLeaderName": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
}
}
},
"dependencies": {

View file

@ -72,6 +72,6 @@ describe('<ControlYamlView />', () => {
);
expect(getByTestId('cloudDefendAdditionalErrors')).toBeTruthy();
expect(getByText('"sessionLeaderName" values cannot exceed 16 bytes')).toBeTruthy();
expect(getByText('"targetFilePath" values cannot exceed 255 bytes')).toBeTruthy();
});
});

View file

@ -55,8 +55,8 @@ export const MOCK_YAML_INVALID_STRING_ARRAY_CONDITION = `file:
operation:
- createExecutable
- modifyExecutable
sessionLeaderName:
- reallylongsessionleadernamethatshouldnotbeallowed
targetFilePath:
- /bin/${new Array(256).fill('a').join()}
responses:
- match:
- default

View file

@ -78,9 +78,7 @@ export type SelectorCondition =
| 'operation'
| 'processExecutable'
| 'processName'
| 'processUserId'
| 'sessionLeaderInteractive'
| 'sessionLeaderName';
| 'sessionLeaderInteractive';
export interface SelectorConditionOptions {
type: SelectorConditionType;
@ -141,9 +139,7 @@ export const SelectorConditionsMap: SelectorConditionsMapProps = {
ignoreVolumeMounts: { selectorType: 'file', type: 'flag', not: ['ignoreVolumeFiles'] },
processExecutable: { selectorType: 'process', type: 'stringArray', not: ['processName'] },
processName: { selectorType: 'process', type: 'stringArray', not: ['processExecutable'] },
processUserId: { selectorType: 'process', type: 'stringArray' },
sessionLeaderInteractive: { selectorType: 'process', type: 'boolean' },
sessionLeaderName: { selectorType: 'process', type: 'stringArray', maxValueBytes: 16 },
};
export type ResponseAction = 'log' | 'alert' | 'block';
@ -168,9 +164,7 @@ export interface Selector {
// process selector properties
processExecutable?: string[];
processName?: string[];
processUserId?: string[];
sessionLeaderInteractive?: string[];
sessionLeaderName?: string[];
// non yaml fields
type: SelectorType;
@ -230,6 +224,7 @@ export interface ViewDeps extends SettingsDeps {
export interface ControlGeneralViewSelectorDeps {
selector: Selector;
selectors: Selector[];
usedByResponse: boolean;
index: number;
onChange(selector: Selector, index: number): void;
onRemove(index: number): void;

View file

@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/kubernetes-security-plugin",
"owner": "@elastic/awp-viz",
"owner": "@elastic/sec-cloudnative-integrations",
"plugin": {
"id": "kubernetesSecurity",
"server": true,

View file

@ -33,7 +33,7 @@ exports[`SessionsView renders correctly against snapshot 1`] = `
Executable
</div>
<div>
User
User ID
</div>
<div>
Interactive

View file

@ -13,7 +13,7 @@ import { DEFAULT_DATE_COLUMN_MIN_WIDTH } from '../../../timelines/components/tim
import {
COLUMN_SESSION_START,
COLUMN_EXECUTABLE,
COLUMN_ENTRY_USER,
COLUMN_ENTRY_USER_ID,
COLUMN_INTERACTIVE,
COLUMN_HOST_NAME,
COLUMN_ENTRY_TYPE,
@ -34,8 +34,8 @@ export const sessionsHeaders: ColumnHeaderOptions[] = [
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'process.entry_leader.user.name',
display: COLUMN_ENTRY_USER,
id: 'process.entry_leader.user.id',
display: COLUMN_ENTRY_USER_ID,
},
{
columnHeaderType: defaultColumnHeaderType,

View file

@ -39,10 +39,10 @@ export const COLUMN_EXECUTABLE = i18n.translate(
}
);
export const COLUMN_ENTRY_USER = i18n.translate(
'xpack.securitySolution.sessionsView.columnEntryUser',
export const COLUMN_ENTRY_USER_ID = i18n.translate(
'xpack.securitySolution.sessionsView.columnEntryUserID',
{
defaultMessage: 'User',
defaultMessage: 'User ID',
}
);

View file

@ -191,7 +191,7 @@ export interface ProcessEvent {
'@timestamp'?: string;
event?: {
kind?: EventKind;
category?: string[];
category?: string | string[];
action?: EventAction | EventAction[];
id?: string;
};

View file

@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/session-view-plugin",
"owner": "@elastic/awp-viz",
"owner": "@elastic/sec-cloudnative-integrations",
"plugin": {
"id": "sessionView",
"server": true,

View file

@ -64,7 +64,9 @@ export const DetailPanelAlertListItem = ({
const { args, name: processName } = event.process ?? {};
const { event: processEvent } = event;
const forceState = !isInvestigated ? 'open' : undefined;
const category = processEvent?.category?.[0];
const category = Array.isArray(processEvent?.category)
? processEvent?.category?.[0]
: processEvent?.category;
const processEventAlertCategory = category ?? ProcessEventAlertCategory.process;
const alertCategoryDetailDisplayText =
category !== ProcessEventAlertCategory.process

View file

@ -266,6 +266,20 @@ export const autoExpandProcessTree = (processMap: ProcessMap, jumpToEntityId?: s
return processMap;
};
// recusively collapses all children below provided node
export const collapseProcessTree = (node: Process) => {
if (!node.autoExpand) {
return;
}
if (node.children) {
node.children.forEach((child) => {
child.autoExpand = false;
collapseProcessTree(child);
});
}
};
export const processNewEvents = (
eventsProcessMap: ProcessMap,
events: ProcessEvent[] | undefined,

View file

@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n';
import { ProcessTreeNode } from '../process_tree_node';
import { BackToInvestigatedAlert } from '../back_to_investigated_alert';
import { useProcessTree } from './hooks';
import { collapseProcessTree } from './helpers';
import { ProcessTreeLoadMoreButton } from '../process_tree_load_more_button';
import {
AlertStatusEventEntityIdMap,
@ -97,6 +98,7 @@ export const ProcessTree = ({
verboseMode,
jumpToEntityId,
});
const [forceRerender, setForceRerender] = useState(0);
const eventsRemaining = useMemo(() => {
const total = data?.[0]?.total || 0;
@ -126,6 +128,14 @@ export const ProcessTree = ({
setIsInvestigatedEventVisible(true);
}, [onProcessSelected]);
const handleCollapseProcessTree = useCallback(() => {
collapseProcessTree(sessionLeader);
if (scrollerRef.current) {
scrollerRef.current.scrollTop = 0;
}
setForceRerender(Math.random());
}, [sessionLeader]);
useEffect(() => {
if (setSearchResults) {
setSearchResults(searchResults);
@ -160,6 +170,7 @@ export const ProcessTree = ({
ref={scrollerRef}
css={styles.sessionViewProcessTree}
data-test-subj="sessionView:sessionViewProcessTree"
key={forceRerender}
>
{sessionLeader && (
<ProcessTreeNode
@ -176,6 +187,7 @@ export const ProcessTree = ({
showTimestamp={showTimestamp}
verboseMode={verboseMode}
searchResults={searchResults}
handleCollapseProcessTree={handleCollapseProcessTree}
loadPreviousButton={
hasPreviousPage ? (
<ProcessTreeLoadMoreButton

View file

@ -23,8 +23,6 @@ export const useStyles = () => {
overflow: 'auto',
height: '100%',
backgroundColor: euiVars.euiColorLightestShade,
paddingTop: size.base,
paddingLeft: size.s,
};
const selectionArea: CSSObject = {

View file

@ -54,6 +54,7 @@ Object {
>
cmd test alert
</div>
</div>
</div>
<div
@ -148,6 +149,7 @@ Object {
>
cmd test alert
</div>
</div>
</div>
<div

View file

@ -64,7 +64,7 @@ describe('ProcessTreeNode component', () => {
renderResult = mockedContext.render(<ProcessTreeNode {...props} isSessionLeader />);
expect(renderResult.container.textContent?.replace(/\s+/g, ' ')).toEqual(
' bash started by vagrant'
' bash started by vagrant '
);
});

View file

@ -20,7 +20,7 @@ import React, {
RefObject,
ReactElement,
} from 'react';
import { EuiButton, EuiIcon, EuiToolTip, formatDate } from '@elastic/eui';
import { EuiButton, EuiIcon, EuiToolTip, formatDate, EuiButtonIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { chain } from 'lodash';
@ -61,6 +61,7 @@ export interface ProcessDeps {
onJumpToOutput: (entityId: string) => void;
loadNextButton?: ReactElement | null;
loadPreviousButton?: ReactElement | null;
handleCollapseProcessTree?: () => void;
}
/**
@ -83,6 +84,7 @@ export function ProcessTreeNode({
onJumpToOutput,
loadPreviousButton,
loadNextButton,
handleCollapseProcessTree,
}: ProcessDeps) {
const [childrenExpanded, setChildrenExpanded] = useState(isSessionLeader || process.autoExpand);
const [alertsExpanded, setAlertsExpanded] = useState(false);
@ -133,7 +135,15 @@ export function ProcessTreeNode({
const alertTypeCounts = useMemo(() => {
const alertCounts: AlertTypeCount[] = chain(alerts)
.groupBy((alert) => alert.event?.category?.[0])
.groupBy((alert) => {
const category = alert.event?.category;
if (Array.isArray(category)) {
return category?.[0];
}
return category;
})
.map((processAlerts, alertCategory) => ({
category: alertCategory as ProcessEventAlertCategory,
count: processAlerts.length,
@ -176,8 +186,12 @@ export function ProcessTreeNode({
}
onProcessSelected?.(process);
if (isSessionLeader && scrollerRef.current) {
scrollerRef.current.scrollTop = 0;
}
},
[onProcessSelected, process]
[isSessionLeader, onProcessSelected, process, scrollerRef]
);
const processDetails = process.getDetails();
@ -219,6 +233,19 @@ export function ProcessTreeNode({
const children = process.getChildren(verboseMode);
const user = processDetails?.process?.user;
const userName = useMemo(() => {
if (user?.name) {
return user.name;
} else if (user?.id === '0') {
return 'root';
} else if (user?.id) {
return `uid: ${user?.id}`;
}
return '-';
}, [user?.id, user?.name]);
if (!processDetails?.process) {
return null;
}
@ -231,7 +258,6 @@ export function ProcessTreeNode({
parent,
working_directory: workingDirectory,
start,
user,
} = processDetails.process;
const shouldRenderChildren = isSessionLeader || (childrenExpanded && children?.length > 0);
@ -275,7 +301,14 @@ export function ProcessTreeNode({
<Nbsp />
<EuiIcon type="user" />
<Nbsp />
<b css={styles.darkText}>{user?.name || 'ID: ' + user?.id}</b>
<b css={styles.darkText}>{userName}</b>
<Nbsp />
<EuiButtonIcon
size="xs"
iconType="fold"
onClick={handleCollapseProcessTree}
css={styles.jumpToTop}
/>
</span>
) : (
<>

View file

@ -95,7 +95,6 @@ export const useStyles = ({
display: 'block',
cursor: 'pointer',
position: 'relative',
marginBottom: isSessionLeader ? size.s : '0px',
'&:hover:before': {
backgroundColor: hoverColor,
},
@ -114,6 +113,10 @@ export const useStyles = ({
},
};
const jumpToTop: CSSObject = {
float: 'right',
};
const textSection: CSSObject = {
marginLeft: size.s,
span: {
@ -131,13 +134,23 @@ export const useStyles = ({
display: 'inline-block',
verticalAlign: 'middle',
},
paddingLeft: PROCESS_TREE_LEFT_PADDING,
};
const searchHighlight = `
color: ${colors.fullShade};
border-radius: '0px';
background-color: ${searchResColor};
`;
if (isSessionLeader) {
processNode.position = 'sticky';
processNode.top = '-' + size.base;
processNode.zIndex = 1;
processNode.borderTop = `${size.base} solid transparent`;
processNode.backgroundColor = euiVars.euiColorLightestShade;
processNode.borderBottom = border.editable;
}
const searchHighlight: CSSObject = {
color: colors.fullShade,
borderRadius: '0px',
backgroundColor: searchResColor,
};
const wrapper: CSSObject = {
paddingLeft: size.s,
@ -188,6 +201,7 @@ export const useStyles = ({
icon,
textSection,
sessionLeader,
jumpToTop,
};
}, [depth, euiTheme, hasAlerts, hasInvestigatedAlert, isSelected, euiVars, isSessionLeader]);

View file

@ -20,7 +20,6 @@ const css: CSSObject = {
display: 'inline',
fontSize: 0,
lineHeight: 0,
verticalAlign: 'middle',
},
};
// Component that takes an array of matching indices in a text and pass down a highlight

View file

@ -201,6 +201,10 @@ export const SessionView = ({
[onProcessSelected, searchResults]
);
useEffect(() => {
onSearchIndexChange(0);
}, [onSearchIndexChange, searchResults]);
const handleOnAlertDetailsClosed = useCallback((alertUuid: string) => {
setFetchAlertStatus([alertUuid]);
}, []);

View file

@ -21,24 +21,22 @@ describe('getAlertCategoryDisplayText(alert, category)', () => {
it('should display rule name when alert category is process', () => {
expect(getAlertCategoryDisplayText(mockAlerts[0], ProcessEventAlertCategory.process)).toEqual(
undefined
''
);
});
it('should display rule name when alert category is undefined', () => {
expect(getAlertCategoryDisplayText(mockAlerts[0], undefined)).toEqual(undefined);
expect(getAlertCategoryDisplayText(mockAlerts[0], undefined)).toEqual('');
});
it('should display rule name when file path is undefined', () => {
const fileAlert = { ...mockFileAlert, file: {} };
expect(getAlertCategoryDisplayText(fileAlert, ProcessEventAlertCategory.file)).toEqual(
undefined
);
expect(getAlertCategoryDisplayText(fileAlert, ProcessEventAlertCategory.file)).toEqual('');
});
it('should display rule name when destination address is undefined and alert category is network', () => {
const networkAlert = { ...mockNetworkAlert, destination: undefined };
expect(getAlertCategoryDisplayText(networkAlert, ProcessEventAlertCategory.network)).toEqual(
undefined
''
);
});
});

View file

@ -19,7 +19,7 @@ export const getAlertCategoryDisplayText = (alert: ProcessEvent, category: strin
if (filePath && category === ProcessEventAlertCategory.file) return dataOrDash(filePath);
if (destination?.address && category === ProcessEventAlertCategory.network)
return dataOrDash(getAlertNetworkDisplay(destination));
return;
return '';
};
export const getAlertNetworkDisplay = (destination: ProcessEventIPAddress) => {

View file

@ -31372,7 +31372,6 @@
"xpack.securitySolution.kpiUsers.totalUsers.title": "Utilisateurs",
"xpack.securitySolution.kubernetes.columnContainer": "Conteneur",
"xpack.securitySolution.kubernetes.columnEntryType": "Type dentrée",
"xpack.securitySolution.kubernetes.columnEntryUser": "Utilisateur dentrée de session",
"xpack.securitySolution.kubernetes.columnExecutable": "Leader de session",
"xpack.securitySolution.kubernetes.columnInteractive": "Interactivité",
"xpack.securitySolution.kubernetes.columnNode": "Nœud",
@ -32041,7 +32040,6 @@
"xpack.securitySolution.selector.summaryView.options.summaryView.description": "Afficher un rendu du flux d'événements pour chaque alerte",
"xpack.securitySolution.sessionsView.columnEntrySourceIp": "IP source",
"xpack.securitySolution.sessionsView.columnEntryType": "Type",
"xpack.securitySolution.sessionsView.columnEntryUser": "Utilisateur",
"xpack.securitySolution.sessionsView.columnExecutable": "Exécutable",
"xpack.securitySolution.sessionsView.columnHostName": "Nom d'hôte",
"xpack.securitySolution.sessionsView.columnInteractive": "Interactif",

View file

@ -31351,7 +31351,6 @@
"xpack.securitySolution.kpiUsers.totalUsers.title": "ユーザー",
"xpack.securitySolution.kubernetes.columnContainer": "コンテナー",
"xpack.securitySolution.kubernetes.columnEntryType": "エントリタイプ",
"xpack.securitySolution.kubernetes.columnEntryUser": "セッションエントリユーザー",
"xpack.securitySolution.kubernetes.columnExecutable": "セッションリーダー",
"xpack.securitySolution.kubernetes.columnInteractive": "インタラクティブ",
"xpack.securitySolution.kubernetes.columnNode": "ノード",
@ -32020,7 +32019,6 @@
"xpack.securitySolution.selector.summaryView.options.summaryView.description": "各アラートのイベントフローのレンダリングを表示",
"xpack.securitySolution.sessionsView.columnEntrySourceIp": "ソース IP",
"xpack.securitySolution.sessionsView.columnEntryType": "型",
"xpack.securitySolution.sessionsView.columnEntryUser": "ユーザー",
"xpack.securitySolution.sessionsView.columnExecutable": "実行ファイル",
"xpack.securitySolution.sessionsView.columnHostName": "ホスト名",
"xpack.securitySolution.sessionsView.columnInteractive": "インタラクティブ",

View file

@ -31367,7 +31367,6 @@
"xpack.securitySolution.kpiUsers.totalUsers.title": "用户",
"xpack.securitySolution.kubernetes.columnContainer": "容器",
"xpack.securitySolution.kubernetes.columnEntryType": "条目类型",
"xpack.securitySolution.kubernetes.columnEntryUser": "会话条目用户",
"xpack.securitySolution.kubernetes.columnExecutable": "会话 Leader",
"xpack.securitySolution.kubernetes.columnInteractive": "交互性",
"xpack.securitySolution.kubernetes.columnNode": "节点",
@ -32036,7 +32035,6 @@
"xpack.securitySolution.selector.summaryView.options.summaryView.description": "查看每个告警的事件渲染",
"xpack.securitySolution.sessionsView.columnEntrySourceIp": "源 IP",
"xpack.securitySolution.sessionsView.columnEntryType": "类型",
"xpack.securitySolution.sessionsView.columnEntryUser": "用户",
"xpack.securitySolution.sessionsView.columnExecutable": "可执行",
"xpack.securitySolution.sessionsView.columnHostName": "主机名",
"xpack.securitySolution.sessionsView.columnInteractive": "交互",