Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SIEM] Detections create prepackage rules #55403

Merged
merged 28 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
512d4fb
update extra action on rule detail to match design
XavierM Jan 15, 2020
88b3ff6
remove experimental label
XavierM Jan 15, 2020
6adf429
allow pre-package to be deleted + do not allow wrong user to create p…
XavierM Jan 15, 2020
3084d05
Additional look back minimum value to 1
XavierM Jan 15, 2020
73b85e5
Merge branch 'master' of github.com:elastic/kibana into detection-eng…
XavierM Jan 15, 2020
578bc79
fix flow with edit rule
XavierM Jan 16, 2020
d7aa454
add success toaster when rule is created or updated
XavierM Jan 16, 2020
b9f6ab0
Merge branch 'master' of github.com:elastic/kibana into detection-eng…
XavierM Jan 16, 2020
3af5581
Fix Timeline selector loading
XavierM Jan 16, 2020
34e7a13
review ben doc + change detectin engine to detection even in url
XavierM Jan 16, 2020
2a554e3
Merge branch 'master' of github.com:elastic/kibana into detection-eng…
XavierM Jan 16, 2020
80bba46
Succeeded text size consistency in rule details page
XavierM Jan 16, 2020
5c34050
fix description of threats
XavierM Jan 16, 2020
aeddd3f
fix test
XavierM Jan 16, 2020
d58a473
fix type
XavierM Jan 17, 2020
a7c5dbf
fix internatinalization
XavierM Jan 17, 2020
1ac3af7
Merge branch 'master' of github.com:elastic/kibana into detections-cr…
XavierM Jan 17, 2020
593ae78
adding pre-packaged rules
XavierM Jan 21, 2020
6eb9906
Merge branch 'master' of github.com:elastic/kibana into detections-cr…
XavierM Jan 21, 2020
4a885f5
fix bug + enhance ux
XavierM Jan 21, 2020
9b56050
Merge branch 'master' of github.com:elastic/kibana into detections-cr…
XavierM Jan 21, 2020
f816171
unified icon
XavierM Jan 21, 2020
657521e
fix i18n
XavierM Jan 21, 2020
5688052
fix bugs
XavierM Jan 21, 2020
35dc9ba
Merge branch 'master' of github.com:elastic/kibana into detections-cr…
XavierM Jan 21, 2020
5dcc6a0
review I
XavierM Jan 21, 2020
f4be8f4
review II
XavierM Jan 22, 2020
4a7fa20
add border back
XavierM Jan 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion x-pack/legacy/plugins/siem/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export const DETECTION_ENGINE_PREPACKAGED_URL = `${DETECTION_ENGINE_RULES_URL}/p
export const DETECTION_ENGINE_PRIVILEGES_URL = `${DETECTION_ENGINE_URL}/privileges`;
export const DETECTION_ENGINE_INDEX_URL = `${DETECTION_ENGINE_URL}/index`;
export const DETECTION_ENGINE_TAGS_URL = `${DETECTION_ENGINE_URL}/tags`;
export const DETECTION_ENGINE_RULES_STATUS = `${DETECTION_ENGINE_URL}/rules/_find_statuses`;
export const DETECTION_ENGINE_RULES_STATUS_URL = `${DETECTION_ENGINE_RULES_URL}/_find_statuses`;
export const DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL = `${DETECTION_ENGINE_RULES_URL}/prepackaged/_status`;

/**
* Default signals index key for kibana.dev.yml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import { throwIfNotOk } from '../../../hooks/api/api';
import {
DETECTION_ENGINE_RULES_URL,
DETECTION_ENGINE_PREPACKAGED_URL,
DETECTION_ENGINE_RULES_STATUS,
DETECTION_ENGINE_RULES_STATUS_URL,
DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL,
} from '../../../../common/constants';
import * as i18n from '../../../pages/detection_engine/rules/translations';

Expand Down Expand Up @@ -63,7 +64,7 @@ export const addRule = async ({ rule, signal }: AddRulesProps): Promise<NewRule>
export const fetchRules = async ({
filterOptions = {
filter: '',
sortField: 'enabled',
sortField: 'name',
sortOrder: 'desc',
},
pagination = {
Expand Down Expand Up @@ -313,6 +314,7 @@ export const exportRules = async ({
* Get Rule Status provided Rule ID
*
* @param id string of Rule ID's (not rule_id)
* @param signal AbortSignal for cancelling request
*
* @throws An error if response is not OK
*/
Expand All @@ -324,7 +326,7 @@ export const getRuleStatusById = async ({
signal: AbortSignal;
}): Promise<Record<string, RuleStatus>> => {
const response = await fetch(
`${chrome.getBasePath()}${DETECTION_ENGINE_RULES_STATUS}?ids=${encodeURIComponent(
`${chrome.getBasePath()}${DETECTION_ENGINE_RULES_STATUS_URL}?ids=${encodeURIComponent(
JSON.stringify([id])
)}`,
{
Expand All @@ -341,3 +343,36 @@ export const getRuleStatusById = async ({
await throwIfNotOk(response);
return response.json();
};

/**
* Get pre packaged rules Status
*
* @param signal AbortSignal for cancelling request
*
* @throws An error if response is not OK
*/
export const getPrePackagedRulesStatus = async ({
signal,
}: {
signal: AbortSignal;
}): Promise<{
rules_installed: number;
rules_not_installed: number;
rules_not_updated: number;
}> => {
const response = await fetch(
`${chrome.getBasePath()}${DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL}`,
{
method: 'GET',
credentials: 'same-origin',
headers: {
'content-type': 'application/json',
'kbn-xsrf': 'true',
},
signal,
}
);

await throwIfNotOk(response);
return response.json();
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export * from './persist_rule';
export * from './types';
export * from './use_rule';
export * from './use_rules';
export * from './use_pre_packaged_rules';
export * from './use_rule_status';
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,17 @@ export const RULE_ADD_FAILURE = i18n.translate(
defaultMessage: 'Failed to add Rule',
}
);

export const RULE_PREPACKAGED_FAILURE = i18n.translate(
'xpack.siem.containers.detectionEngine.createPrePackagedRuleFailDescription',
{
defaultMessage: 'Failed to installed pre-packaged rules from elastic',
}
);

export const RULE_PREPACKAGED_SUCCESS = i18n.translate(
'xpack.siem.containers.detectionEngine.createPrePackagedRuleSuccesDescription',
{
defaultMessage: 'Installed pre-packaged rules from elastic',
}
);

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { useEffect, useState, useRef } from 'react';

import { useStateToaster, displaySuccessToast } from '../../../components/toasters';
import { errorToToaster } from '../../../components/ml/api/error_to_toaster';
import { getPrePackagedRulesStatus, createPrepackagedRules } from './api';
import * as i18n from './translations';

type Func = () => void;
export type CreatePreBuiltRules = () => Promise<boolean>;
interface Return {
createPrePackagedRules: null | CreatePreBuiltRules;
loading: boolean;
loadingCreatePrePackagedRules: boolean;
refetchPrePackagedRulesStatus: Func | null;
rulesInstalled: number | null;
rulesNotInstalled: number | null;
rulesNotUpdated: number | null;
}

interface UsePrePackagedRuleProps {
canUserCRUD: boolean | null;
hasIndexManage: boolean | null;
hasManageApiKey: boolean | null;
isAuthenticated: boolean | null;
isSignalIndexExists: boolean | null;
}

/**
* Hook for using to get status about pre-packaged Rules from the Detection Engine API
*
* @param hasIndexManage boolean
* @param hasManageApiKey boolean
* @param isAuthenticated boolean
* @param isSignalIndexExists boolean
*
*/
export const usePrePackagedRules = ({
canUserCRUD,
hasIndexManage,
hasManageApiKey,
isAuthenticated,
isSignalIndexExists,
}: UsePrePackagedRuleProps): Return => {
const [rulesInstalled, setRulesInstalled] = useState<number | null>(null);
const [rulesNotInstalled, setRulesNotInstalled] = useState<number | null>(null);
const [rulesNotUpdated, setRulesNotUpdated] = useState<number | null>(null);
const [loadingCreatePrePackagedRules, setLoadingCreatePrePackagedRules] = useState(false);
const [loading, setLoading] = useState(true);
const createPrePackagedRules = useRef<null | CreatePreBuiltRules>(null);
const refetchPrePackagedRules = useRef<Func | null>(null);
const [, dispatchToaster] = useStateToaster();

useEffect(() => {
let isSubscribed = true;
const abortCtrl = new AbortController();

const fetchPrePackagedRules = async () => {
try {
setLoading(true);
const prePackagedRuleStatusResponse = await getPrePackagedRulesStatus({
signal: abortCtrl.signal,
});

if (isSubscribed) {
setRulesInstalled(prePackagedRuleStatusResponse.rules_installed);
setRulesNotInstalled(prePackagedRuleStatusResponse.rules_not_installed);
setRulesNotUpdated(prePackagedRuleStatusResponse.rules_not_updated);
}
} catch (error) {
if (isSubscribed) {
setRulesInstalled(null);
setRulesNotInstalled(null);
setRulesNotUpdated(null);
errorToToaster({ title: i18n.RULE_FETCH_FAILURE, error, dispatchToaster });
}
}
if (isSubscribed) {
setLoading(false);
}
};

const createElasticRules = async (): Promise<boolean> => {
return new Promise(async resolve => {
try {
if (
canUserCRUD &&
hasIndexManage &&
hasManageApiKey &&
isAuthenticated &&
isSignalIndexExists
) {
setLoadingCreatePrePackagedRules(true);
await createPrepackagedRules({
signal: abortCtrl.signal,
});

if (isSubscribed) {
let iterationTryOfFetchingPrePackagedCount = 0;
let timeoutId = -1;
const stopTimeOut = () => {
if (timeoutId !== -1) {
window.clearTimeout(timeoutId);
}
};
const reFetch = () =>
window.setTimeout(async () => {
iterationTryOfFetchingPrePackagedCount =
iterationTryOfFetchingPrePackagedCount + 1;
const prePackagedRuleStatusResponse = await getPrePackagedRulesStatus({
signal: abortCtrl.signal,
});
if (
isSubscribed &&
((prePackagedRuleStatusResponse.rules_not_installed === 0 &&
prePackagedRuleStatusResponse.rules_not_updated === 0) ||
iterationTryOfFetchingPrePackagedCount > 100)
) {
setLoadingCreatePrePackagedRules(false);
setRulesInstalled(prePackagedRuleStatusResponse.rules_installed);
setRulesNotInstalled(prePackagedRuleStatusResponse.rules_not_installed);
setRulesNotUpdated(prePackagedRuleStatusResponse.rules_not_updated);
displaySuccessToast(i18n.RULE_PREPACKAGED_SUCCESS, dispatchToaster);
stopTimeOut();
resolve(true);
} else {
timeoutId = reFetch();
}
}, 300);
timeoutId = reFetch();
}
}
} catch (error) {
if (isSubscribed) {
setLoadingCreatePrePackagedRules(false);
errorToToaster({ title: i18n.RULE_PREPACKAGED_FAILURE, error, dispatchToaster });
resolve(false);
}
}
});
};

fetchPrePackagedRules();
createPrePackagedRules.current = createElasticRules;
refetchPrePackagedRules.current = fetchPrePackagedRules;
return () => {
isSubscribed = false;
abortCtrl.abort();
};
}, [canUserCRUD, hasIndexManage, hasManageApiKey, isAuthenticated, isSignalIndexExists]);

return {
loading,
loadingCreatePrePackagedRules,
refetchPrePackagedRulesStatus: refetchPrePackagedRules.current,
rulesInstalled,
rulesNotInstalled,
rulesNotUpdated,
createPrePackagedRules: createPrePackagedRules.current,
};
};
Loading