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

Vulnerability dashboard error loading for read only user #6993

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to the Wazuh app project will be documented in this file.

### Fixed

- Fixed issue causing vulnerability dashboard to fail loading for read-only users [#6933](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6993)
- Fixed the temporal directory variable on the the command to deploy a new Windows agent [#6905](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6905)
- Fixed an error on the command to deploy a new macOS agent that could cause the registration password had a wrong value because a `\n` could be included [#6906](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6906)
- Fixed rendering an active response as disabled when is active [#6901](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6901)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
PatternDataSourceFilterManager,
tFilterManager,
} from '../index';
import { TimeRange } from '../../../../../../../src/plugins/data/public';
import { createOsdUrlStateStorage } from '../../../../../../../src/plugins/opensearch_dashboards_utils/public';
import NavigationService from '../../../../react-services/navigation-service';
import { OSD_URL_STATE_STORAGE_ID } from '../../../../../common/constants';
Expand Down Expand Up @@ -56,7 +55,6 @@ type tUseDataSourceLoadedReturns<K> = {
fetchData: (params: Omit<tSearchParams, 'filters'>) => Promise<any>;
setFilters: (filters: tFilter[]) => void;
filterManager: PatternDataSourceFilterManager;
fetchDateRange: TimeRange;
};

type tUseDataSourceNotLoadedReturns = {
Expand Down Expand Up @@ -92,8 +90,10 @@ export function useDataSource<
useHash: config.get(OSD_URL_STATE_STORAGE_ID),
history: history,
});
const appDefaultFilters = osdUrlStateStorage.get('_a')?.filters ?? [];
const globalDefaultFilters = osdUrlStateStorage.get('_g')?.filters ?? [];
const appDefaultFilters =
osdUrlStateStorage.get<{ filters: [] }>('_a')?.filters ?? [];
const globalDefaultFilters =
osdUrlStateStorage.get<{ filters: [] }>('_g')?.filters ?? [];
const defaultFilters = [...appDefaultFilters, ...globalDefaultFilters];
const {
filters: initialFilters = [...defaultFilters],
Expand All @@ -118,7 +118,6 @@ export function useDataSource<
const [allFilters, setAllFilters] = useState<tFilter[]>([]);
const pinnedAgentManager = new PinnedAgentManager();
const pinnedAgent = pinnedAgentManager.getPinnedAgent();
const [fetchDateRange, setFetchDateRange] = useState<TimeRange>();
const { isComponentMounted, getAbortController } = useIsMounted();

const setFilters = (filters: tFilter[]) => {
Expand All @@ -144,43 +143,47 @@ export function useDataSource<

(async () => {
setIsLoading(true);
const factory = injectedFactory || new PatternDataSourceFactory();
const patternsData = await repository.getAll();
const dataSources = await factory.createAll(
DataSourceConstructor,
patternsData,
);
const selector = new PatternDataSourceSelector(dataSources, repository);
const dataSource = await selector.getSelectedDataSource();
if (!dataSource) {
throw new Error('No valid data source found');
try {
const factory = injectedFactory || new PatternDataSourceFactory();
const patternsData = await repository.getAll();
const dataSources = await factory.createAll(
DataSourceConstructor,
patternsData,
);
const selector = new PatternDataSourceSelector(dataSources, repository);
const dataSource = await selector.getSelectedDataSource();
if (!dataSource) {
throw new Error('No valid data source found');
}
if (!isComponentMounted()) return;
setDataSource(dataSource);
const dataSourceFilterManager = new PatternDataSourceFilterManager(
dataSource,
initialFilters,
injectedFilterManager,
initialFetchFilters,
);
// what the filters update
subscription = dataSourceFilterManager.getUpdates$().subscribe({
next: () => {
if (!isComponentMounted()) return;
// this is necessary to remove the hidden filters from the filter manager and not show them in the search bar
dataSourceFilterManager.setFilters(
dataSourceFilterManager.getFilters(),
);
setAllFilters(dataSourceFilterManager.getFilters());
setFetchFilters(dataSourceFilterManager.getFetchFilters());
setFixedFilters(dataSourceFilterManager.getFixedFilters());
},
});
setAllFilters(dataSourceFilterManager.getFilters());
setFetchFilters(dataSourceFilterManager.getFetchFilters());
setFixedFilters(dataSourceFilterManager.getFixedFilters());
setDataSourceFilterManager(dataSourceFilterManager);
} catch {
} finally {
setIsLoading(false);
}
if (!isComponentMounted()) return;
setDataSource(dataSource);
const dataSourceFilterManager = new PatternDataSourceFilterManager(
dataSource,
initialFilters,
injectedFilterManager,
initialFetchFilters,
);
// what the filters update
subscription = dataSourceFilterManager.getUpdates$().subscribe({
next: () => {
if (!isComponentMounted()) return;
// this is necessary to remove the hidden filters from the filter manager and not show them in the search bar
dataSourceFilterManager.setFilters(
dataSourceFilterManager.getFilters(),
);
setAllFilters(dataSourceFilterManager.getFilters());
setFetchFilters(dataSourceFilterManager.getFetchFilters());
setFixedFilters(dataSourceFilterManager.getFixedFilters());
},
});
setAllFilters(dataSourceFilterManager.getFilters());
setFetchFilters(dataSourceFilterManager.getFetchFilters());
setFixedFilters(dataSourceFilterManager.getFixedFilters());
setDataSourceFilterManager(dataSourceFilterManager);
setIsLoading(false);
})();

return () => {
Expand Down Expand Up @@ -218,7 +221,6 @@ export function useDataSource<
fetchData,
setFilters,
filterManager: dataSourceFilterManager as PatternDataSourceFilterManager,
fetchDateRange,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { IndexPatternsService } from '../../../../../../../src/plugins/data/common';
import { RecordMock } from '../../../../../test/types';
import { PatternDataSource } from './pattern-data-source';

let patternService: RecordMock<IndexPatternsService>;
let patternDataSource: PatternDataSource;
const TEST_ID = 'test-id';
const TEST_TITLE = 'test-title';

describe('PatternDataSource', () => {
beforeEach(() => {
patternDataSource = new PatternDataSource(TEST_ID, TEST_TITLE);
// @ts-expect-error
patternService = {
get: jest.fn().mockImplementation(() => ({
getScriptedFields: jest.fn().mockImplementation(() => []),
fields: {
replaceAll: jest.fn(),
},
})),
getFieldsForIndexPattern: jest.fn().mockResolvedValue([]),
updateSavedObject: jest.fn(),
};
// @ts-expect-error
patternDataSource.patternService = patternService;
});

it('should throw error when pattern not found', () => {
patternService.get.mockResolvedValue(undefined);
expect(async () => {
await patternDataSource.select();
}).rejects.toThrow(
'Error selecting index pattern: Error: Error selecting index pattern: pattern not found',
);
});

it('should throw error when get fields for index pattern rejects', () => {
patternService.getFieldsForIndexPattern.mockRejectedValue(null);
expect(async () => {
await patternDataSource.select();
}).rejects.toThrow('Error selecting index pattern: null');
});

it('should not throw error when selecting from pattern data source', async () => {
await expect(patternDataSource.select()).resolves.not.toThrow();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '../index';
import { getDataPlugin } from '../../../../kibana-services';
import {
IndexPatternsContract,
IndexPatternsService,
IndexPattern,
} from '../../../../../../../src/plugins/data/public';
import { search } from '../../search-bar/search-bar-service';
Expand All @@ -16,7 +16,7 @@ export class PatternDataSource implements tDataSource {
id: string;
title: string;
fields: any[];
patternService: IndexPatternsContract;
patternService: IndexPatternsService;
indexPattern: IndexPattern;

constructor(id: string, title: string) {
Expand Down Expand Up @@ -44,21 +44,24 @@ export class PatternDataSource implements tDataSource {
}

async select() {
let pattern: IndexPattern;
try {
const pattern = await this.patternService.get(this.id);
if (pattern) {
const fields = await this.patternService.getFieldsForIndexPattern(
pattern,
);
const scripted = pattern.getScriptedFields().map(field => field.spec);
pattern.fields.replaceAll([...fields, ...scripted]);
await this.patternService.updateSavedObject(pattern);
} else {
pattern = await this.patternService.get(this.id);
if (!pattern)
throw new Error('Error selecting index pattern: pattern not found');
}

const fields = await this.patternService.getFieldsForIndexPattern(
pattern,
);
const scripted = pattern.getScriptedFields().map(field => field.spec);
pattern.fields.replaceAll([...fields, ...scripted]);
} catch (error) {
throw new Error(`Error selecting index pattern: ${error}`);
}
try {
// Vulnerability dashboard error loading for read only user
await this.patternService.updateSavedObject(pattern);
} catch {}
}

async fetch(params: tSearchParams) {
Expand Down
14 changes: 14 additions & 0 deletions plugins/main/test/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export type RecordMock<T> = {
[K in keyof T]: T[K] extends Function
? jest.Mock
: T[K] extends {}
? RecordMock<T[K]>
: T[K];
};
export type PartialRecordMock<T> = Partial<{
[K in keyof T]: T[K] extends Function
? jest.Mock
: T[K] extends {}
? PartialRecordMock<T[K]>
: T[K];
}>;
Loading