Skip to content

Commit 4e8fda2

Browse files
Merge branch 'master' into fix/siem-alerts-table-filters
2 parents 49a0b36 + 0689010 commit 4e8fda2

57 files changed

Lines changed: 825 additions & 230 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

NOTICE.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,40 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153153
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
154154
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
155155

156+
---
157+
This product bundles rules based on https://github.com/BlueTeamLabs/sentinel-attack
158+
which is available under a "MIT" license. The files based on this license are:
159+
160+
- windows_defense_evasion_via_filter_manager.json
161+
- windows_process_discovery_via_tasklist_command.json
162+
- windows_priv_escalation_via_accessibility_features.json
163+
- windows_persistence_via_application_shimming.json
164+
- windows_execution_via_trusted_developer_utilities.json
165+
- windows_execution_via_net_com_assemblies.json
166+
- windows_execution_via_connection_manager.json
167+
168+
MIT License
169+
170+
Copyright (c) 2019 Edoardo Gerosa, Olaf Hartong
171+
172+
Permission is hereby granted, free of charge, to any person obtaining a copy of
173+
this software and associated documentation files (the "Software"), to deal in
174+
the Software without restriction, including without limitation the rights to
175+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
176+
of the Software, and to permit persons to whom the Software is furnished to do
177+
so, subject to the following conditions:
178+
179+
The above copyright notice and this permission notice shall be included in all
180+
copies or substantial portions of the Software.
181+
182+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
183+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
185+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
186+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
187+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
188+
SOFTWARE.
189+
156190
---
157191
This product includes code that is adapted from mapbox-gl-js, which is
158192
available under a "BSD-3-Clause" license.

src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ describe('getSortedObjectsForExport()', () => {
108108
"namespace": undefined,
109109
"perPage": 500,
110110
"search": undefined,
111-
"sortField": "_id",
112-
"sortOrder": "asc",
113111
"type": Array [
114112
"index-pattern",
115113
"search",
@@ -256,8 +254,6 @@ describe('getSortedObjectsForExport()', () => {
256254
"namespace": undefined,
257255
"perPage": 500,
258256
"search": "foo",
259-
"sortField": "_id",
260-
"sortOrder": "asc",
261257
"type": Array [
262258
"index-pattern",
263259
"search",
@@ -345,8 +341,6 @@ describe('getSortedObjectsForExport()', () => {
345341
"namespace": "foo",
346342
"perPage": 500,
347343
"search": undefined,
348-
"sortField": "_id",
349-
"sortOrder": "asc",
350344
"type": Array [
351345
"index-pattern",
352346
"search",
@@ -399,6 +393,79 @@ describe('getSortedObjectsForExport()', () => {
399393
).rejects.toThrowErrorMatchingInlineSnapshot(`"Can't export more than 1 objects"`);
400394
});
401395

396+
test('sorts objects within type', async () => {
397+
savedObjectsClient.find.mockResolvedValueOnce({
398+
total: 3,
399+
per_page: 10000,
400+
page: 1,
401+
saved_objects: [
402+
{
403+
id: '3',
404+
type: 'index-pattern',
405+
attributes: {
406+
name: 'baz',
407+
},
408+
references: [],
409+
},
410+
{
411+
id: '1',
412+
type: 'index-pattern',
413+
attributes: {
414+
name: 'foo',
415+
},
416+
references: [],
417+
},
418+
{
419+
id: '2',
420+
type: 'index-pattern',
421+
attributes: {
422+
name: 'bar',
423+
},
424+
references: [],
425+
},
426+
],
427+
});
428+
const exportStream = await getSortedObjectsForExport({
429+
exportSizeLimit: 10000,
430+
savedObjectsClient,
431+
types: ['index-pattern'],
432+
});
433+
const response = await readStreamToCompletion(exportStream);
434+
expect(response).toMatchInlineSnapshot(`
435+
Array [
436+
Object {
437+
"attributes": Object {
438+
"name": "foo",
439+
},
440+
"id": "1",
441+
"references": Array [],
442+
"type": "index-pattern",
443+
},
444+
Object {
445+
"attributes": Object {
446+
"name": "bar",
447+
},
448+
"id": "2",
449+
"references": Array [],
450+
"type": "index-pattern",
451+
},
452+
Object {
453+
"attributes": Object {
454+
"name": "baz",
455+
},
456+
"id": "3",
457+
"references": Array [],
458+
"type": "index-pattern",
459+
},
460+
Object {
461+
"exportedCount": 3,
462+
"missingRefCount": 0,
463+
"missingReferences": Array [],
464+
},
465+
]
466+
`);
467+
});
468+
402469
test('exports selected objects and sorts them', async () => {
403470
savedObjectsClient.bulkGet.mockResolvedValueOnce({
404471
saved_objects: [

src/core/server/saved_objects/export/get_sorted_objects_for_export.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import Boom from 'boom';
2121
import { createListStream } from '../../../../legacy/utils/streams';
22-
import { SavedObjectsClientContract } from '../types';
22+
import { SavedObjectsClientContract, SavedObject } from '../types';
2323
import { fetchNestedDependencies } from './inject_nested_depdendencies';
2424
import { sortObjects } from './sort_objects';
2525

@@ -105,15 +105,17 @@ async function fetchObjectsToExport({
105105
const findResponse = await savedObjectsClient.find({
106106
type: types,
107107
search,
108-
sortField: '_id',
109-
sortOrder: 'asc',
110108
perPage: exportSizeLimit,
111109
namespace,
112110
});
113111
if (findResponse.total > exportSizeLimit) {
114112
throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`);
115113
}
116-
return findResponse.saved_objects;
114+
115+
// sorts server-side by _id, since it's only available in fielddata
116+
return findResponse.saved_objects.sort((a: SavedObject, b: SavedObject) =>
117+
a.id > b.id ? 1 : -1
118+
);
117119
} else {
118120
throw Boom.badRequest('Either `type` or `objects` are required.');
119121
}
@@ -137,14 +139,17 @@ export async function getSortedObjectsForExport({
137139
exportSizeLimit,
138140
namespace,
139141
});
140-
let exportedObjects = [...rootObjects];
142+
let exportedObjects = [];
141143
let missingReferences: SavedObjectsExportResultDetails['missingReferences'] = [];
144+
142145
if (includeReferencesDeep) {
143146
const fetchResult = await fetchNestedDependencies(rootObjects, savedObjectsClient, namespace);
144-
exportedObjects = fetchResult.objects;
147+
exportedObjects = sortObjects(fetchResult.objects);
145148
missingReferences = fetchResult.missingRefs;
149+
} else {
150+
exportedObjects = sortObjects(rootObjects);
146151
}
147-
exportedObjects = sortObjects(exportedObjects);
152+
148153
const exportDetails: SavedObjectsExportResultDetails = {
149154
exportedCount: exportedObjects.length,
150155
missingRefCount: missingReferences.length,

x-pack/legacy/plugins/infra/public/components/metrics_explorer/chart.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export const MetricsExplorerChart = ({
8686
<EuiTitle size="xs">
8787
<EuiFlexGroup alignItems="center">
8888
<ChartTitle>
89-
<EuiToolTip content={title}>
89+
<EuiToolTip content={title} anchorClassName="metricsExplorerTitleAnchor">
9090
<span>{title}</span>
9191
</EuiToolTip>
9292
</ChartTitle>
@@ -159,7 +159,7 @@ export const MetricsExplorerChart = ({
159159
};
160160

161161
const ChartTitle = euiStyled.div`
162-
width: 100%
162+
width: 100%;
163163
overflow: hidden;
164164
text-overflow: ellipsis;
165165
white-space: nowrap;

x-pack/legacy/plugins/infra/public/index.scss

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636

3737
.infrastructureChart .echTooltip__label {
3838
overflow-x: hidden;
39-
white-space: no-wrap;
39+
white-space: nowrap;
4040
text-overflow: ellipsis;
4141
}
42+
43+
.metricsExplorerTitleAnchor {
44+
white-space: nowrap;
45+
text-overflow: ellipsis;
46+
display: inline;
47+
}

x-pack/legacy/plugins/siem/public/components/alerts_viewer/default_headers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const alertsHeaders: ColumnHeader[] = [
1919
columnHeaderType: defaultColumnHeaderType,
2020
id: 'event.module',
2121
width: DEFAULT_COLUMN_MIN_WIDTH,
22+
linkField: 'rule.reference',
2223
},
2324
{
2425
columnHeaderType: defaultColumnHeaderType,

x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/constants.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ export const DATE_FIELD_TYPE = 'date';
88
export const HOST_NAME_FIELD_NAME = 'host.name';
99
export const IP_FIELD_TYPE = 'ip';
1010
export const MESSAGE_FIELD_NAME = 'message';
11+
export const EVENT_MODULE_FIELD_NAME = 'event.module';
12+
export const RULE_REFERENCE_FIELD_NAME = 'rule.reference';
1113
export const SIGNAL_RULE_NAME_FIELD_NAME = 'signal.rule.name';

x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/formatted_field.tsx

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { EuiFlexGroup, EuiFlexItem, EuiToolTip, EuiLink } from '@elastic/eui';
7+
import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
88
import { isNumber, isString, isEmpty } from 'lodash/fp';
99
import React from 'react';
1010

@@ -15,16 +15,19 @@ import { getOrEmptyTagFromValue, getEmptyTagValue } from '../../../empty_value';
1515
import { FormattedDate } from '../../../formatted_date';
1616
import { FormattedIp } from '../../../formatted_ip';
1717
import { HostDetailsLink } from '../../../links';
18-
import { getRuleDetailsUrl } from '../../../link_to/redirect_to_detection_engine';
18+
1919
import { Port, PORT_NAMES } from '../../../port';
2020
import { TruncatableText } from '../../../truncatable_text';
2121
import {
2222
DATE_FIELD_TYPE,
2323
HOST_NAME_FIELD_NAME,
2424
IP_FIELD_TYPE,
2525
MESSAGE_FIELD_NAME,
26+
EVENT_MODULE_FIELD_NAME,
27+
RULE_REFERENCE_FIELD_NAME,
2628
SIGNAL_RULE_NAME_FIELD_NAME,
2729
} from './constants';
30+
import { renderRuleName, renderEventModule, renderRulReference } from './formatted_field_helpers';
2831

2932
// simple black-list to prevent dragging and dropping fields such as message name
3033
const columnNamesNotDraggable = [MESSAGE_FIELD_NAME];
@@ -88,6 +91,12 @@ const FormattedFieldValueComponent: React.FC<{
8891
return (
8992
<Bytes contextId={contextId} eventId={eventId} fieldName={fieldName} value={`${value}`} />
9093
);
94+
} else if (fieldName === SIGNAL_RULE_NAME_FIELD_NAME) {
95+
return renderRuleName({ contextId, eventId, fieldName, linkValue, truncate, value });
96+
} else if (fieldName === EVENT_MODULE_FIELD_NAME) {
97+
return renderEventModule({ contextId, eventId, fieldName, linkValue, truncate, value });
98+
} else if (fieldName === RULE_REFERENCE_FIELD_NAME) {
99+
return renderRulReference({ contextId, eventId, fieldName, linkValue, truncate, value });
91100
} else if (columnNamesNotDraggable.includes(fieldName)) {
92101
return truncate && !isEmpty(value) ? (
93102
<TruncatableText data-test-subj="truncatable-message">
@@ -110,24 +119,6 @@ const FormattedFieldValueComponent: React.FC<{
110119
) : (
111120
<>{value}</>
112121
);
113-
} else if (fieldName === SIGNAL_RULE_NAME_FIELD_NAME) {
114-
const ruleName = `${value}`;
115-
const ruleId = linkValue;
116-
117-
return isString(value) && ruleName.length > 0 && ruleId != null ? (
118-
<DefaultDraggable
119-
field={fieldName}
120-
id={`event-details-value-default-draggable-${contextId}-${eventId}-${fieldName}-${value}-${ruleId}`}
121-
tooltipContent={value}
122-
value={value}
123-
>
124-
<EuiLink href={getRuleDetailsUrl(ruleId)}>
125-
<TruncatableText data-test-subj="draggable-truncatable-content">{value}</TruncatableText>
126-
</EuiLink>
127-
</DefaultDraggable>
128-
) : (
129-
getEmptyTagValue()
130-
);
131122
} else {
132123
const contentValue = getOrEmptyTagFromValue(value);
133124
const content = truncate ? <TruncatableText>{contentValue}</TruncatableText> : contentValue;

0 commit comments

Comments
 (0)