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

Add initialization service #7145

Merged
merged 34 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7f186d6
feat(initialization): add initialization service
Desvelao Nov 8, 2024
710774b
fix: call method of saved object service
Desvelao Nov 8, 2024
5f94e00
chore: remove console.log
Desvelao Nov 8, 2024
f76784a
feat(initialization): add API endpoints to manage the initialization …
Desvelao Nov 11, 2024
11e40e9
feat(initialization): enhance documentation
Desvelao Nov 11, 2024
c5aaf7c
feat(initialization): add tests
Desvelao Nov 12, 2024
4c0a863
feat(initialization): enhance task related to check connection and co…
Desvelao Nov 12, 2024
d5b0b9f
fix(initialization): minor fixes in tasks
Desvelao Nov 12, 2024
1b052be
feat(initialization): add default fields for vulnerability-states ind…
Desvelao Nov 12, 2024
2777291
Merge branch 'master' of https://github.com/wazuh/wazuh-kibana-app in…
Desvelao Nov 12, 2024
168c4d7
Merge branch 'master' into enhancement/7133-add-initialization-service
asteriscos Nov 21, 2024
fb4eb7f
fix: import statement related to specific function instead of all module
Desvelao Nov 22, 2024
5920547
Apply suggestions from code review
Desvelao Nov 22, 2024
a68e03d
fix: rename setting
Desvelao Nov 22, 2024
409115f
fix(initialization): apply review suggestions related to creation of …
Desvelao Nov 25, 2024
d123f31
fix(initialization): move InitializationTask class to another file
Desvelao Nov 25, 2024
5e03e8b
fix(initialization): add types
Desvelao Nov 26, 2024
d194092
fix(initialization): typo
Desvelao Nov 26, 2024
fdc987c
fix(initialization): move temporal registration to core plugin
Desvelao Nov 26, 2024
e3b1cc4
fix(initialization): add missing default index pattern fields for alerts
Desvelao Nov 26, 2024
90c99aa
fix(initialization): enhance types and rename error variable
Desvelao Nov 26, 2024
83ea856
fix(initialization): variable name in test
Desvelao Nov 26, 2024
92f6d0c
fix(initialization): enhance types and rename error variable
Desvelao Nov 26, 2024
fa3b79a
fix(initialization): enhance types
Desvelao Nov 26, 2024
b27efff
Merge branch 'master' of https://github.com/wazuh/wazuh-kibana-app in…
Desvelao Nov 26, 2024
0fbe92a
fix(prettier): initalization task
Desvelao Nov 26, 2024
bff0b53
chore(changelog): add entry
Desvelao Nov 27, 2024
c01b2aa
Update plugins/wazuh-core/common/services/initialization/constants.ts
Desvelao Nov 28, 2024
1df7f7a
Update plugins/wazuh-core/common/services/initialization/types.ts
Desvelao Nov 28, 2024
b993f59
fix(initialization): adapt initialization task to new constants
Desvelao Nov 29, 2024
2f3af97
Merge branch 'master' of https://github.com/wazuh/wazuh-kibana-app in…
Desvelao Nov 29, 2024
57e345e
fix(initlization): lint
Desvelao Dec 2, 2024
97961ca
fix(initlization): lint
Desvelao Dec 2, 2024
c27446a
fix(test): service name
Desvelao Dec 2, 2024
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
8 changes: 8 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module.exports = {
'react-hooks',
'@typescript-eslint',
'unicorn',
'import',
'prettier',
'@stylistic',
],
Expand Down Expand Up @@ -210,6 +211,12 @@ module.exports = {
'@typescript-eslint/naming-convention': [
'error',
{ selector: 'default', format: ['camelCase'] },
{ selector: 'import', format: ['camelCase', 'PascalCase'] },
{
selector: 'variable',
types: ['function'],
format: ['camelCase', 'PascalCase'],
},
{
selector: ['objectLiteralProperty', 'typeProperty'],
format: null,
Expand All @@ -225,6 +232,7 @@ module.exports = {
{
selector: ['variable'],
modifiers: ['global'],
types: ['number', 'string'],
format: ['UPPER_CASE'],
},
{
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to the Wazuh app project will be documented in this file.

- Support for Wazuh 5.0.0
- Added creation of report definition when creating dashboard by reference and the button to reset the report [#7091](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7091)
- Added an initilization service to core plugin to run the initilization tasks related to user scope [#7145](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7145)

### Removed

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { EuiButton, EuiEmptyPrompt, EuiLink } from '@elastic/eui';
import { withGuardAsync } from '../../../../common/hocs';
import { getSavedObjects } from '../../../../../kibana-services';
import { SavedObject } from '../../../../../react-services';
import { NOT_TIME_FIELD_NAME_INDEX_PATTERN } from '../../../../../../common/constants';
import { EuiButton, EuiEmptyPrompt, EuiLink } from '@elastic/eui';
import { webDocumentationLink } from '../../../../../../common/services/web_documentation';
import { vulnerabilityDetection } from '../../../../../utils/applications';
import { LoadingSpinnerDataSource } from '../../../../common/loading/loading-spinner-data-source';
import NavigationService from '../../../../../react-services/navigation-service';
import { NavigationService } from '../../../../../react-services/navigation-service';

const INDEX_PATTERN_CREATION_NO_INDEX = 'INDEX_PATTERN_CREATION_NO_INDEX';

Expand All @@ -20,15 +20,16 @@ async function checkExistenceIndexPattern(indexPatternID: string) {
async function checkExistenceIndices(indexPatternId: string) {
try {
const fields = await SavedObject.getIndicesFields(indexPatternId);

return { exist: true, fields };
} catch (error) {
} catch {
return { exist: false };
}
}

async function createIndexPattern(indexPattern, fields: any) {
try {
await SavedObject.createSavedObjectIndexPattern(
await SavedObject.createSavedObject(
'index-pattern',
indexPattern,
{
Expand All @@ -51,7 +52,7 @@ export async function validateVulnerabilitiesStateDataSources({
try {
// Check the existence of related index pattern
const existIndexPattern = await checkExistenceIndexPattern(indexPatternID);
let indexPattern = existIndexPattern;
const indexPattern = existIndexPattern;

// If the idnex pattern does not exist, then check the existence of index
if (existIndexPattern?.error?.statusCode === 404) {
Expand All @@ -70,11 +71,13 @@ export async function validateVulnerabilitiesStateDataSources({
},
};
}

// If the some index match the index pattern, then create the index pattern
const resultCreateIndexPattern = await createIndexPattern(
indexPatternID,
fields,
);

if (resultCreateIndexPattern?.error) {
return {
ok: true,
Expand All @@ -86,6 +89,7 @@ export async function validateVulnerabilitiesStateDataSources({
},
};
}

/* WORKAROUND: Redirect to the root of Vulnerabilities Detection application that should
redirects to the Dashboard tab. We want to redirect to this view, because we need the
component is visible (visualizations) to ensure the process that defines the filters for the
Expand All @@ -95,6 +99,7 @@ export async function validateVulnerabilitiesStateDataSources({
*/
NavigationService.getInstance().navigateToApp(vulnerabilityDetection.id);
}

return {
ok: false,
data: { indexPattern },
Expand Down Expand Up @@ -127,10 +132,13 @@ const errorPromptBody = {
),
};

export const PromptCheckIndex = props => {
export const PromptCheckIndex = (props: {
error: { title: string; message: string; type?: string };
refresh: () => void;
}) => {
const { refresh } = props;
const { title, message } = props?.error;
const body = errorPromptBody?.[props?.error?.type] || <p>{message}</p>;
const { title, message } = props.error;
const body = errorPromptBody?.[props.error?.type] || <p>{message}</p>;

return (
<EuiEmptyPrompt
Expand All @@ -146,10 +154,12 @@ export const PromptCheckIndex = props => {
);
};

const mapStateToProps = state => ({
vulnerabilitiesStatesindexPatternID:
state.appConfig.data['vulnerabilities.pattern'],
});
const mapStateToProps = state => {
return {
vulnerabilitiesStatesindexPatternID:
state.appConfig.data['vulnerabilities.pattern'],
};
};

export const withVulnerabilitiesStateDataSource = compose(
connect(mapStateToProps),
Expand Down
93 changes: 55 additions & 38 deletions plugins/main/public/react-services/navigation-service.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Location, Action, History } from 'history';
import rison from 'rison-node';
import { getCore } from '../kibana-services';
import { NavigateToAppOptions } from '../../../../src/core/public';
import { getIndexPattern } from './elastic_helpers';
import { buildPhraseFilter } from '../../../../src/plugins/data/common';
import rison from 'rison-node';
import { getIndexPattern } from './elastic_helpers';

class NavigationService {
// eslint-disable-next-line no-use-before-define
private static instance: NavigationService;
private history: History;
private readonly history: History;

private constructor(history: History) {
this.history = history;
Expand All @@ -19,6 +20,7 @@ class NavigationService {
} else if (!NavigationService.instance) {
throw new Error('NavigationService must be initialized with a history.');
}

return NavigationService.instance;
}

Expand Down Expand Up @@ -56,30 +58,31 @@ class NavigationService {
? this.buildSearch(params)
: this.buildSearch(this.getParams());
const locationHash = this.getHash();

this.navigate(
`${newPath}${queryParams ? `?${queryParams}` : ''}${locationHash}`,
);
}

public navigate(path: string, state?: any): void {
if (!state) {
this.history.push(path);
} else {
if (state) {
this.history.push({
pathname: path,
state,
});
} else {
this.history.push(path);
}
}

public replace(path: string, state?: any): void {
if (!state) {
this.history.replace(path);
} else {
if (state) {
this.history.replace({
pathname: path,
state,
});
} else {
this.history.replace(path);
}
}

Expand All @@ -96,13 +99,14 @@ class NavigationService {
}

public reload(): void {
window.location.reload();
globalThis.location.reload();
}

public listen(
listener: (location: Location, action: Action) => void,
): () => void {
const unlisten = this.history.listen(listener);

return unlisten;
}

Expand All @@ -125,43 +129,45 @@ class NavigationService {
}

public buildSearch(search: URLSearchParams) {
return Array.from(search.entries())
return [...search.entries()]
.map(([key, value]) => `${key}=${value}`)
.join('&');
}

public updateAndNavigateSearchParams(params: {
[key: string]: string | null;
}): void {
public updateAndNavigateSearchParams(
params: Record<string, string | null>,
): void {
const urlParams = this.getParams();

// Update or delete parameters according to their value
Object.entries(params).forEach(([key, value]) => {
for (const [key, value] of Object.entries(params)) {
if (value === null) {
urlParams.delete(key);
} else {
urlParams.set(key, value);
}
});
}

const queryString = this.buildSearch(urlParams);

this.navigate(`${this.getPathname()}?${queryString}`);
}

public switchTab(newTab: string): void {
this.updateAndNavigateSearchParams({ tab: newTab });
}

public switchSubTab = (subTab: string): void => {
public switchSubTab(subTab: string): void {
this.updateAndNavigateSearchParams({ tabView: subTab });
};
}

/*
TODO: Analyze and improve this function taking into account whether buildFilter_w is still used and whether the implementation with respect to the middle button is correct in navigateToModule
TODO: Analyze and improve this function taking into account whether buildFilterW is still used and whether the implementation with respect to the middle button is correct in navigateToModule
*/
private buildFilter_w(filters, indexPattern) {
private buildFilterW(filters, indexPattern) {
const filtersArray: any[] = [];
Object.keys(filters).forEach(currentFilter => {

for (const currentFilter of Object.keys(filters)) {
filtersArray.push({
...buildPhraseFilter(
{ name: currentFilter, type: 'text' },
Expand All @@ -170,41 +176,51 @@ class NavigationService {
),
$state: { isImplicit: false, store: 'appState' },
});
});
}

return rison.encode({ filters: filtersArray });
}

navigateToModule(e: any, section: string, params: any, navigateMethod?: any) {
e.persist(); // needed to access this event asynchronously
if (e.button == 0) {
// left button clicked
if (navigateMethod) {
navigateMethod();
return;
}
navigateToModule(
event: any,
section: string,
params: any,
navigateMethod?: any,
) {
event.persist(); // needed to access this event asynchronously

if (
event.button === 0 && // left button clicked
navigateMethod
) {
navigateMethod();

return;
}

getIndexPattern().then(indexPattern => {
const urlParams = {};

if (Object.keys(params).length) {
Object.keys(params).forEach(key => {
if (Object.keys(params).length > 0) {
for (const key of Object.keys(params)) {
if (key === 'filters') {
urlParams['_w'] = this.buildFilter_w(params[key], indexPattern);
urlParams['_w'] = this.buildFilterW(params[key], indexPattern);
} else {
urlParams[key] = params[key];
}
});
}
}

const url = Object.entries(urlParams)
.map(e => e.join('='))
.map(urlParam => urlParam.join('='))
.join('&');
const currentUrl = window.location.href.split('#/')[0];
const currentUrl = globalThis.location.href.split('#/')[0];
const newUrl = currentUrl + `#/${section}?` + url;

if (e && (e.which == 2 || e.button == 1)) {
if (event && (event.which === 2 || event.button === 1)) {
// middlebutton clicked
window.open(newUrl, '_blank', 'noreferrer');
} else if (e.button == 0) {
} else if (event.button === 0) {
// left button clicked
if (navigateMethod) {
navigateMethod();
Expand All @@ -217,3 +233,4 @@ class NavigationService {
}

export default NavigationService;
export { NavigationService };
16 changes: 16 additions & 0 deletions plugins/wazuh-core/common/services/initialization/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const initializationTask = {
RUN_STATUS: {
NOT_STARTED: 'not_started',
RUNNING: 'running',
FINISHED: 'finished',
},
RUN_RESULT: {
NULL: null,
SUCCESS: 'success',
FAIL: 'fail',
},
CONTEXT: {
INTERNAL: 'internal',
USER: 'user',
},
} as const;
13 changes: 13 additions & 0 deletions plugins/wazuh-core/common/services/initialization/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { initializationTask } from './constants';

type RunStatusEnum = (typeof initializationTask)['RUN_STATUS'];

export type InitializationTaskRunStatus = RunStatusEnum[keyof RunStatusEnum];

type RunResultEnum = (typeof initializationTask)['RUN_RESULT'];

export type InitializationTaskRunResult = RunResultEnum[keyof RunResultEnum];

type ContextEnum = (typeof initializationTask)['CONTEXT'];

export type InitializationTaskContext = ContextEnum[keyof ContextEnum];
2 changes: 1 addition & 1 deletion plugins/wazuh-core/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ export function plugin(initializerContext: PluginInitializerContext) {
return new WazuhCorePlugin(initializerContext);
}

export type { WazuhCorePluginSetup, WazuhCorePluginStart } from './types';
export * from './types';
export type { IConfigurationEnhanced } from './services/enhance-configuration';
Loading
Loading