mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Fleet] Enforce unique names on download binary sources (#136648)
* [Fleet] Enforce unique names on download binary sources * Add new SO to plugin.ts for privileges handling
This commit is contained in:
parent
3508350446
commit
8c239088e0
3 changed files with 83 additions and 3 deletions
|
@ -53,6 +53,7 @@ import {
|
|||
PACKAGES_SAVED_OBJECT_TYPE,
|
||||
ASSETS_SAVED_OBJECT_TYPE,
|
||||
PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
|
||||
DOWNLOAD_SOURCE_SAVED_OBJECT_TYPE,
|
||||
} from './constants';
|
||||
import { registerSavedObjects, registerEncryptedSavedObjects } from './saved_objects';
|
||||
import {
|
||||
|
@ -141,6 +142,7 @@ const allSavedObjectTypes = [
|
|||
PACKAGES_SAVED_OBJECT_TYPE,
|
||||
ASSETS_SAVED_OBJECT_TYPE,
|
||||
PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
|
||||
DOWNLOAD_SOURCE_SAVED_OBJECT_TYPE,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,7 @@ function mockDownloadSourceSO(id: string, attributes: any = {}) {
|
|||
};
|
||||
}
|
||||
|
||||
function getMockedSoClient(options: { defaultDownloadSourceId?: string } = {}) {
|
||||
function getMockedSoClient(options: { defaultDownloadSourceId?: string; sameName?: boolean } = {}) {
|
||||
const soClient = savedObjectsClientMock.create();
|
||||
|
||||
soClient.get.mockImplementation(async (type: string, id: string) => {
|
||||
|
@ -95,6 +95,25 @@ function getMockedSoClient(options: { defaultDownloadSourceId?: string } = {}) {
|
|||
};
|
||||
}
|
||||
|
||||
if (
|
||||
options.sameName &&
|
||||
findOptions.searchFields &&
|
||||
findOptions.searchFields.includes('name') &&
|
||||
findOptions
|
||||
) {
|
||||
return {
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
saved_objects: [
|
||||
{
|
||||
score: 0,
|
||||
...(await soClient.get(DOWNLOAD_SOURCE_SAVED_OBJECT_TYPE, 'download-source-test')),
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
|
@ -102,12 +121,13 @@ function getMockedSoClient(options: { defaultDownloadSourceId?: string } = {}) {
|
|||
total: 0,
|
||||
};
|
||||
});
|
||||
|
||||
mockedAppContextService.getInternalUserSOClient.mockReturnValue(soClient);
|
||||
|
||||
return soClient;
|
||||
}
|
||||
|
||||
describe('Download Service Service', () => {
|
||||
describe('Download Service', () => {
|
||||
beforeEach(() => {
|
||||
mockedAgentPolicyService.list.mockClear();
|
||||
mockedAgentPolicyService.hasAPMIntegration.mockClear();
|
||||
|
@ -256,4 +276,24 @@ describe('Download Service Service', () => {
|
|||
expect(defaultId).toEqual('existing-default-download-source');
|
||||
});
|
||||
});
|
||||
|
||||
describe('requireUniqueName', () => {
|
||||
it('throws an error if the name already exists', () => {
|
||||
const soClient = getMockedSoClient({
|
||||
defaultDownloadSourceId: 'download-source-test',
|
||||
sameName: true,
|
||||
});
|
||||
expect(
|
||||
async () => await downloadSourceService.requireUniqueName(soClient, { name: 'Test' })
|
||||
).rejects.toThrow(`Download Source 'download-source-test' already exists with name 'Test'`);
|
||||
});
|
||||
it('does not throw if the name is unique', () => {
|
||||
const soClient = getMockedSoClient({
|
||||
defaultDownloadSourceId: 'download-source-test',
|
||||
});
|
||||
expect(
|
||||
async () => await downloadSourceService.requireUniqueName(soClient, { name: 'Test' })
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,11 +13,12 @@ import {
|
|||
} from '../constants';
|
||||
|
||||
import type { DownloadSource, DownloadSourceAttributes, DownloadSourceBase } from '../types';
|
||||
import { DownloadSourceError } from '../errors';
|
||||
import { DownloadSourceError, IngestManagerError } from '../errors';
|
||||
import { SO_SEARCH_LIMIT } from '../../common';
|
||||
|
||||
import { agentPolicyService } from './agent_policy';
|
||||
import { appContextService } from './app_context';
|
||||
import { escapeSearchQueryPhrase } from './saved_object';
|
||||
|
||||
function savedObjectToDownloadSource(so: SavedObject<DownloadSourceAttributes>) {
|
||||
const { source_id: sourceId, ...attributes } = so.attributes;
|
||||
|
@ -66,6 +67,11 @@ class DownloadSourceService {
|
|||
): Promise<DownloadSource> {
|
||||
const data: DownloadSourceAttributes = downloadSource;
|
||||
|
||||
await this.requireUniqueName(soClient, {
|
||||
name: downloadSource.name,
|
||||
id: options?.id,
|
||||
});
|
||||
|
||||
// default should be only one
|
||||
if (data.is_default) {
|
||||
const defaultDownloadSourceId = await this.getDefaultDownloadSourceId(soClient);
|
||||
|
@ -96,6 +102,13 @@ class DownloadSourceService {
|
|||
) {
|
||||
const updateData: Partial<DownloadSourceAttributes> = newData;
|
||||
|
||||
if (newData.name) {
|
||||
await this.requireUniqueName(soClient, {
|
||||
name: newData.name,
|
||||
id,
|
||||
});
|
||||
}
|
||||
|
||||
if (updateData.is_default) {
|
||||
const defaultDownloadSourceId = await this.getDefaultDownloadSourceId(soClient);
|
||||
|
||||
|
@ -164,6 +177,31 @@ class DownloadSourceService {
|
|||
return defaultDS;
|
||||
}
|
||||
|
||||
public async requireUniqueName(
|
||||
soClient: SavedObjectsClientContract,
|
||||
downloadSource: { name: string; id?: string }
|
||||
) {
|
||||
const results = await soClient.find<DownloadSourceAttributes>({
|
||||
type: DOWNLOAD_SOURCE_SAVED_OBJECT_TYPE,
|
||||
searchFields: ['name'],
|
||||
search: escapeSearchQueryPhrase(downloadSource.name),
|
||||
});
|
||||
const idsWithName = results.total && results.saved_objects.map(({ id }) => id);
|
||||
|
||||
if (Array.isArray(idsWithName)) {
|
||||
const isEditingSelf = downloadSource?.id && idsWithName.includes(downloadSource.id);
|
||||
if (!downloadSource.id || !isEditingSelf) {
|
||||
const isSingle = idsWithName.length === 1;
|
||||
|
||||
const existClause = isSingle
|
||||
? `Download Source '${idsWithName[0]}' already exists`
|
||||
: `Download Sources '${idsWithName.join(',')}' already exist`;
|
||||
|
||||
throw new IngestManagerError(`${existClause} with name '${downloadSource.name}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _getDefaultDownloadSourceSO(soClient: SavedObjectsClientContract) {
|
||||
return await soClient.find<DownloadSourceAttributes>({
|
||||
type: DOWNLOAD_SOURCE_SAVED_OBJECT_TYPE,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue