Skip to content

Commit b715d51

Browse files
Merge branch 'master' into ML-74938-fix-spaces-encoding
2 parents 4ae259b + b9c8201 commit b715d51

File tree

40 files changed

+1551
-514
lines changed

40 files changed

+1551
-514
lines changed

docs/developer/best-practices/index.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ guidelines]
4848
* Write all new code on
4949
{kib-repo}blob/{branch}/src/core/README.md[the
5050
platform], and following
51-
{kib-repo}blob/{branch}/src/core/CONVENTIONS.md[conventions]
51+
{kib-repo}blob/{branch}/src/core/CONVENTIONS.md[conventions].
5252
* _Always_ use the `SavedObjectClient` for reading and writing Saved
5353
Objects.
5454
* Add `README`s to all your plugins and services.

docs/developer/best-practices/stability.asciidoc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ storeinSessions?)
5252
[discrete]
5353
=== Browser coverage
5454

55-
Refer to the list of browsers and OS {kib} supports
55+
Refer to the list of browsers and OS {kib} supports:
5656
https://www.elastic.co/support/matrix
5757

5858
Does the feature work efficiently on the list of supported browsers?
5959

6060
[discrete]
61-
=== Upgrade Scenarios - Migration scenarios-
61+
=== Upgrade and Migration scenarios
6262

63-
Does the feature affect old
64-
indices, saved objects ? - Has the feature been tested with {kib}
65-
aliases - Read/Write privileges of the indices before and after the
63+
* Does the feature affect old indices or saved objects?
64+
* Has the feature been tested with {kib} aliases?
65+
* Read/Write privileges of the indices before and after the
6666
upgrade?

docs/developer/getting-started/building-kibana.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[[building-kibana]]
22
== Building a {kib} distributable
33

4-
The following commands will build a {kib} production distributable.
4+
The following command will build a {kib} production distributable:
55

66
[source,bash]
77
----
@@ -36,4 +36,4 @@ To specify a package to build you can add `rpm` or `deb` as an argument.
3636
yarn build --rpm
3737
----
3838

39-
Distributable packages can be found in `target/` after the build completes.
39+
Distributable packages can be found in `target/` after the build completes.

docs/developer/getting-started/index.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ ____
4949

5050
(You can also run `yarn kbn` to see the other available commands. For
5151
more info about this tool, see
52-
{kib-repo}tree/{branch}/packages/kbn-pm[{kib-repo}tree/{branch}packages/kbn-pm].)
52+
{kib-repo}tree/{branch}/packages/kbn-pm[{kib-repo}tree/{branch}/packages/kbn-pm].)
5353

5454
When switching branches which use different versions of npm packages you
5555
may need to run:
@@ -137,4 +137,4 @@ include::debugging.asciidoc[leveloffset=+1]
137137

138138
include::building-kibana.asciidoc[leveloffset=+1]
139139

140-
include::development-plugin-resources.asciidoc[leveloffset=+1]
140+
include::development-plugin-resources.asciidoc[leveloffset=+1]

docs/developer/getting-started/running-kibana-advanced.asciidoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ settings].
7373
[discrete]
7474
=== Potential Optimization Pitfalls
7575

76-
* Webpack is trying to include a file in the bundle that I deleted and
77-
is now complaining about it is missing
76+
* Webpack is trying to include a file in the bundle that was deleted and
77+
is now complaining about it being missing
7878
* A module id that used to resolve to a single file now resolves to a
7979
directory, but webpack isn’t adapting
8080
* (if you discover other scenarios, please send a PR!)
@@ -84,4 +84,4 @@ directory, but webpack isn’t adapting
8484

8585
{kib} includes self-signed certificates that can be used for
8686
development purposes in the browser and for communicating with
87-
{es}: `yarn start --ssl` & `yarn es snapshot --ssl`.
87+
{es}: `yarn start --ssl` & `yarn es snapshot --ssl`.

x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ describe('data generator', () => {
169169
const childrenPerNode = 3;
170170
const generations = 3;
171171
const relatedAlerts = 4;
172+
172173
beforeEach(() => {
173174
tree = generator.generateTree({
174175
alwaysGenMaxChildrenPerNode: true,
@@ -182,6 +183,7 @@ describe('data generator', () => {
182183
{ category: RelatedEventCategory.File, count: 2 },
183184
{ category: RelatedEventCategory.Network, count: 1 },
184185
],
186+
relatedEventsOrdered: true,
185187
relatedAlerts,
186188
ancestryArraySize: ANCESTRY_LIMIT,
187189
});
@@ -212,6 +214,14 @@ describe('data generator', () => {
212214
}
213215
};
214216

217+
it('creates related events in ascending order', () => {
218+
// the order should not change since it should already be in ascending order
219+
const relatedEventsAsc = _.cloneDeep(tree.origin.relatedEvents).sort(
220+
(event1, event2) => event1['@timestamp'] - event2['@timestamp']
221+
);
222+
expect(tree.origin.relatedEvents).toStrictEqual(relatedEventsAsc);
223+
});
224+
215225
it('has ancestry array defined', () => {
216226
expect(tree.origin.lifecycle[0].process.Ext!.ancestry!.length).toBe(ANCESTRY_LIMIT);
217227
for (const event of tree.allEvents) {

x-pack/plugins/security_solution/common/endpoint/generate_data.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,12 @@ export interface TreeOptions {
302302
generations?: number;
303303
children?: number;
304304
relatedEvents?: RelatedEventInfo[] | number;
305+
/**
306+
* If true then the related events will be created with timestamps that preserve the
307+
* generation order, meaning the first event will always have a timestamp number less
308+
* than the next related event
309+
*/
310+
relatedEventsOrdered?: boolean;
305311
relatedAlerts?: number;
306312
percentWithRelated?: number;
307313
percentTerminated?: number;
@@ -322,6 +328,7 @@ export function getTreeOptionsWithDef(options?: TreeOptions): TreeOptionDefaults
322328
generations: options?.generations ?? 2,
323329
children: options?.children ?? 2,
324330
relatedEvents: options?.relatedEvents ?? 5,
331+
relatedEventsOrdered: options?.relatedEventsOrdered ?? false,
325332
relatedAlerts: options?.relatedAlerts ?? 3,
326333
percentWithRelated: options?.percentWithRelated ?? 30,
327334
percentTerminated: options?.percentTerminated ?? 100,
@@ -809,7 +816,8 @@ export class EndpointDocGenerator {
809816
for (const relatedEvent of this.relatedEventsGenerator(
810817
node,
811818
opts.relatedEvents,
812-
secBeforeEvent
819+
secBeforeEvent,
820+
opts.relatedEventsOrdered
813821
)) {
814822
eventList.push(relatedEvent);
815823
}
@@ -877,6 +885,8 @@ export class EndpointDocGenerator {
877885
addRelatedAlerts(ancestor, numAlertsPerNode, processDuration, events);
878886
}
879887
}
888+
timestamp = timestamp + 1000;
889+
880890
events.push(
881891
this.generateAlert(
882892
timestamp,
@@ -961,7 +971,12 @@ export class EndpointDocGenerator {
961971
});
962972
}
963973
if (this.randomN(100) < opts.percentWithRelated) {
964-
yield* this.relatedEventsGenerator(child, opts.relatedEvents, processDuration);
974+
yield* this.relatedEventsGenerator(
975+
child,
976+
opts.relatedEvents,
977+
processDuration,
978+
opts.relatedEventsOrdered
979+
);
965980
yield* this.relatedAlertsGenerator(child, opts.relatedAlerts, processDuration);
966981
}
967982
}
@@ -973,13 +988,17 @@ export class EndpointDocGenerator {
973988
* @param relatedEvents - can be an array of RelatedEventInfo objects describing the related events that should be generated for each process node
974989
* or a number which defines the number of related events and will default to random categories
975990
* @param processDuration - maximum number of seconds after process event that related event timestamp can be
991+
* @param ordered - if true the events will have an increasing timestamp, otherwise their timestamp will be random but
992+
* guaranteed to be greater than or equal to the originating event
976993
*/
977994
public *relatedEventsGenerator(
978995
node: Event,
979996
relatedEvents: RelatedEventInfo[] | number = 10,
980-
processDuration: number = 6 * 3600
997+
processDuration: number = 6 * 3600,
998+
ordered: boolean = false
981999
) {
9821000
let relatedEventsInfo: RelatedEventInfo[];
1001+
let ts = node['@timestamp'] + 1;
9831002
if (typeof relatedEvents === 'number') {
9841003
relatedEventsInfo = [{ category: RelatedEventCategory.Random, count: relatedEvents }];
9851004
} else {
@@ -995,7 +1014,12 @@ export class EndpointDocGenerator {
9951014
eventInfo = OTHER_EVENT_CATEGORIES[event.category];
9961015
}
9971016

998-
const ts = node['@timestamp'] + this.randomN(processDuration) * 1000;
1017+
if (ordered) {
1018+
ts += this.randomN(processDuration) * 1000;
1019+
} else {
1020+
ts = node['@timestamp'] + this.randomN(processDuration) * 1000;
1021+
}
1022+
9991023
yield this.generateEvent({
10001024
timestamp: ts,
10011025
entityID: node.process.entity_id,

x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ export const validateEvents = {
3333
afterEvent: schema.maybe(schema.string()),
3434
legacyEndpointID: schema.maybe(schema.string({ minLength: 1 })),
3535
}),
36+
body: schema.nullable(
37+
schema.object({
38+
filter: schema.maybe(schema.string()),
39+
})
40+
),
3641
};
3742

3843
/**
@@ -45,6 +50,11 @@ export const validateAlerts = {
4550
afterAlert: schema.maybe(schema.string()),
4651
legacyEndpointID: schema.maybe(schema.string({ minLength: 1 })),
4752
}),
53+
body: schema.nullable(
54+
schema.object({
55+
filter: schema.maybe(schema.string()),
56+
})
57+
),
4858
};
4959

5060
/**

x-pack/plugins/security_solution/public/common/components/exceptions/add_exception_modal/index.tsx

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
EuiCheckbox,
1919
EuiSpacer,
2020
EuiFormRow,
21-
EuiCallOut,
2221
EuiText,
2322
} from '@elastic/eui';
2423
import { Status } from '../../../../../common/detection_engine/schemas/common/schemas';
@@ -28,13 +27,15 @@ import {
2827
ExceptionListType,
2928
} from '../../../../../public/lists_plugin_deps';
3029
import * as i18n from './translations';
30+
import * as sharedI18n from '../translations';
3131
import { TimelineNonEcsData, Ecs } from '../../../../graphql/types';
3232
import { useAppToasts } from '../../../hooks/use_app_toasts';
3333
import { useKibana } from '../../../lib/kibana';
3434
import { ExceptionBuilderComponent } from '../builder';
3535
import { Loader } from '../../loader';
3636
import { useAddOrUpdateException } from '../use_add_exception';
3737
import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index';
38+
import { useRuleAsync } from '../../../../detections/containers/detection_engine/rules/use_rule_async';
3839
import { useFetchOrCreateRuleExceptionList } from '../use_fetch_or_create_rule_exception_list';
3940
import { AddExceptionComments } from '../add_exception_comments';
4041
import {
@@ -46,6 +47,7 @@ import {
4647
entryHasNonEcsType,
4748
getMappedNonEcsValue,
4849
} from '../helpers';
50+
import { ErrorInfo, ErrorCallout } from '../error_callout';
4951
import { useFetchIndexPatterns } from '../../../../detections/containers/detection_engine/rules';
5052

5153
export interface AddExceptionModalBaseProps {
@@ -107,13 +109,14 @@ export const AddExceptionModal = memo(function AddExceptionModal({
107109
}: AddExceptionModalProps) {
108110
const { http } = useKibana().services;
109111
const [comment, setComment] = useState('');
112+
const { rule: maybeRule } = useRuleAsync(ruleId);
110113
const [shouldCloseAlert, setShouldCloseAlert] = useState(false);
111114
const [shouldBulkCloseAlert, setShouldBulkCloseAlert] = useState(false);
112115
const [shouldDisableBulkClose, setShouldDisableBulkClose] = useState(false);
113116
const [exceptionItemsToAdd, setExceptionItemsToAdd] = useState<
114117
Array<ExceptionListItemSchema | CreateExceptionListItemSchema>
115118
>([]);
116-
const [fetchOrCreateListError, setFetchOrCreateListError] = useState(false);
119+
const [fetchOrCreateListError, setFetchOrCreateListError] = useState<ErrorInfo | null>(null);
117120
const { addError, addSuccess } = useAppToasts();
118121
const { loading: isSignalIndexLoading, signalIndexName } = useSignalIndex();
119122
const [
@@ -164,17 +167,41 @@ export const AddExceptionModal = memo(function AddExceptionModal({
164167
},
165168
[onRuleChange]
166169
);
167-
const onFetchOrCreateExceptionListError = useCallback(
168-
(error: Error) => {
169-
setFetchOrCreateListError(true);
170+
171+
const handleDissasociationSuccess = useCallback(
172+
(id: string): void => {
173+
handleRuleChange(true);
174+
addSuccess(sharedI18n.DISSASOCIATE_LIST_SUCCESS(id));
175+
onCancel();
176+
},
177+
[handleRuleChange, addSuccess, onCancel]
178+
);
179+
180+
const handleDissasociationError = useCallback(
181+
(error: Error): void => {
182+
addError(error, { title: sharedI18n.DISSASOCIATE_EXCEPTION_LIST_ERROR });
183+
onCancel();
184+
},
185+
[addError, onCancel]
186+
);
187+
188+
const handleFetchOrCreateExceptionListError = useCallback(
189+
(error: Error, statusCode: number | null, message: string | null) => {
190+
setFetchOrCreateListError({
191+
reason: error.message,
192+
code: statusCode,
193+
details: message,
194+
listListId: null,
195+
});
170196
},
171197
[setFetchOrCreateListError]
172198
);
199+
173200
const [isLoadingExceptionList, ruleExceptionList] = useFetchOrCreateRuleExceptionList({
174201
http,
175202
ruleId,
176203
exceptionListType,
177-
onError: onFetchOrCreateExceptionListError,
204+
onError: handleFetchOrCreateExceptionListError,
178205
onSuccess: handleRuleChange,
179206
});
180207

@@ -279,7 +306,9 @@ export const AddExceptionModal = memo(function AddExceptionModal({
279306
]);
280307

281308
const isSubmitButtonDisabled = useMemo(
282-
() => fetchOrCreateListError || exceptionItemsToAdd.every((item) => item.entries.length === 0),
309+
() =>
310+
fetchOrCreateListError != null ||
311+
exceptionItemsToAdd.every((item) => item.entries.length === 0),
283312
[fetchOrCreateListError, exceptionItemsToAdd]
284313
);
285314

@@ -295,19 +324,27 @@ export const AddExceptionModal = memo(function AddExceptionModal({
295324
</ModalHeaderSubtitle>
296325
</ModalHeader>
297326

298-
{fetchOrCreateListError === true && (
299-
<EuiCallOut title={i18n.ADD_EXCEPTION_FETCH_ERROR_TITLE} color="danger" iconType="alert">
300-
<p>{i18n.ADD_EXCEPTION_FETCH_ERROR}</p>
301-
</EuiCallOut>
327+
{fetchOrCreateListError != null && (
328+
<EuiModalFooter>
329+
<ErrorCallout
330+
http={http}
331+
errorInfo={fetchOrCreateListError}
332+
rule={maybeRule}
333+
onCancel={onCancel}
334+
onSuccess={handleDissasociationSuccess}
335+
onError={handleDissasociationError}
336+
data-test-subj="addExceptionModalErrorCallout"
337+
/>
338+
</EuiModalFooter>
302339
)}
303-
{fetchOrCreateListError === false &&
340+
{fetchOrCreateListError == null &&
304341
(isLoadingExceptionList ||
305342
isIndexPatternLoading ||
306343
isSignalIndexLoading ||
307344
isSignalIndexPatternLoading) && (
308345
<Loader data-test-subj="loadingAddExceptionModal" size="xl" />
309346
)}
310-
{fetchOrCreateListError === false &&
347+
{fetchOrCreateListError == null &&
311348
!isSignalIndexLoading &&
312349
!isSignalIndexPatternLoading &&
313350
!isLoadingExceptionList &&
@@ -377,20 +414,21 @@ export const AddExceptionModal = memo(function AddExceptionModal({
377414
</ModalBodySection>
378415
</>
379416
)}
417+
{fetchOrCreateListError == null && (
418+
<EuiModalFooter>
419+
<EuiButtonEmpty onClick={onCancel}>{i18n.CANCEL}</EuiButtonEmpty>
380420

381-
<EuiModalFooter>
382-
<EuiButtonEmpty onClick={onCancel}>{i18n.CANCEL}</EuiButtonEmpty>
383-
384-
<EuiButton
385-
data-test-subj="add-exception-confirm-button"
386-
onClick={onAddExceptionConfirm}
387-
isLoading={addExceptionIsLoading}
388-
isDisabled={isSubmitButtonDisabled}
389-
fill
390-
>
391-
{i18n.ADD_EXCEPTION}
392-
</EuiButton>
393-
</EuiModalFooter>
421+
<EuiButton
422+
data-test-subj="add-exception-confirm-button"
423+
onClick={onAddExceptionConfirm}
424+
isLoading={addExceptionIsLoading}
425+
isDisabled={isSubmitButtonDisabled}
426+
fill
427+
>
428+
{i18n.ADD_EXCEPTION}
429+
</EuiButton>
430+
</EuiModalFooter>
431+
)}
394432
</Modal>
395433
</EuiOverlayMask>
396434
);

0 commit comments

Comments
 (0)