As part of the work needed for RBAC & Feature Controls support in Alerting (https://github.com/elastic/kibana/issues/43994) we've identified a need to make the Alert Saved Object type a _hidden_ type. As we still need support for Security and Spaces, we wish to use the standard SavedObjectsClient and its middleware, but currently this isn't possible with _hidden_ types. To address that, this PR adds support for creating a client which includes hidden types.
This commit is contained in:
parent
67fdbfdd71
commit
68c9cda277
44 changed files with 615 additions and 185 deletions
|
@ -9,7 +9,8 @@ Describes the factory used to create instances of the Saved Objects Client.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type SavedObjectsClientFactory = ({ request, }: {
|
||||
export declare type SavedObjectsClientFactory = ({ request, includedHiddenTypes, }: {
|
||||
request: KibanaRequest;
|
||||
includedHiddenTypes?: string[];
|
||||
}) => SavedObjectsClientContract;
|
||||
```
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsClientProviderOptions](./kibana-plugin-core-server.savedobjectsclientprovideroptions.md) > [includedHiddenTypes](./kibana-plugin-core-server.savedobjectsclientprovideroptions.includedhiddentypes.md)
|
||||
|
||||
## SavedObjectsClientProviderOptions.includedHiddenTypes property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
includedHiddenTypes?: string[];
|
||||
```
|
|
@ -17,4 +17,5 @@ export interface SavedObjectsClientProviderOptions
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [excludedWrappers](./kibana-plugin-core-server.savedobjectsclientprovideroptions.excludedwrappers.md) | <code>string[]</code> | |
|
||||
| [includedHiddenTypes](./kibana-plugin-core-server.savedobjectsclientprovideroptions.includedhiddentypes.md) | <code>string[]</code> | |
|
||||
|
||||
|
|
|
@ -9,5 +9,5 @@ Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsre
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createInternalRepository: (includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
```
|
||||
|
|
|
@ -9,5 +9,5 @@ Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsre
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (req: KibanaRequest, includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
```
|
||||
|
|
|
@ -16,6 +16,6 @@ export interface SavedObjectsRepositoryFactory
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [createInternalRepository](./kibana-plugin-core-server.savedobjectsrepositoryfactory.createinternalrepository.md) | <code>(extraTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the internal Kibana user for authenticating with Elasticsearch. |
|
||||
| [createScopedRepository](./kibana-plugin-core-server.savedobjectsrepositoryfactory.createscopedrepository.md) | <code>(req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. |
|
||||
| [createInternalRepository](./kibana-plugin-core-server.savedobjectsrepositoryfactory.createinternalrepository.md) | <code>(includedHiddenTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the internal Kibana user for authenticating with Elasticsearch. |
|
||||
| [createScopedRepository](./kibana-plugin-core-server.savedobjectsrepositoryfactory.createscopedrepository.md) | <code>(req: KibanaRequest, includedHiddenTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. |
|
||||
|
||||
|
|
|
@ -9,5 +9,5 @@ Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsre
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createInternalRepository: (includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@ Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsre
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (req: KibanaRequest, includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
|
|
@ -16,8 +16,8 @@ export interface SavedObjectsServiceStart
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [createInternalRepository](./kibana-plugin-core-server.savedobjectsservicestart.createinternalrepository.md) | <code>(extraTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the internal Kibana user for authenticating with Elasticsearch. |
|
||||
| [createScopedRepository](./kibana-plugin-core-server.savedobjectsservicestart.createscopedrepository.md) | <code>(req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. |
|
||||
| [createInternalRepository](./kibana-plugin-core-server.savedobjectsservicestart.createinternalrepository.md) | <code>(includedHiddenTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the internal Kibana user for authenticating with Elasticsearch. |
|
||||
| [createScopedRepository](./kibana-plugin-core-server.savedobjectsservicestart.createscopedrepository.md) | <code>(req: KibanaRequest, includedHiddenTypes?: string[]) => ISavedObjectsRepository</code> | Creates a [Saved Objects repository](./kibana-plugin-core-server.isavedobjectsrepository.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. |
|
||||
| [createSerializer](./kibana-plugin-core-server.savedobjectsservicestart.createserializer.md) | <code>() => SavedObjectsSerializer</code> | Creates a [serializer](./kibana-plugin-core-server.savedobjectsserializer.md) that is aware of all registered types. |
|
||||
| [getScopedClient](./kibana-plugin-core-server.savedobjectsservicestart.getscopedclient.md) | <code>(req: KibanaRequest, options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract</code> | Creates a [Saved Objects client](./kibana-plugin-core-server.savedobjectsclientcontract.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. If other plugins have registered Saved Objects client wrappers, these will be applied to extend the functionality of the client.<!-- -->A client that is already scoped to the incoming request is also exposed from the route handler context see [RequestHandlerContext](./kibana-plugin-core-server.requesthandlercontext.md)<!-- -->. |
|
||||
| [getTypeRegistry](./kibana-plugin-core-server.savedobjectsservicestart.gettyperegistry.md) | <code>() => ISavedObjectTypeRegistry</code> | Returns the [registry](./kibana-plugin-core-server.isavedobjecttyperegistry.md) containing all registered [saved object types](./kibana-plugin-core-server.savedobjectstype.md) |
|
||||
|
|
|
@ -35,6 +35,10 @@ import { legacyServiceMock } from '../legacy/legacy_service.mock';
|
|||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
import { SavedObjectsClientFactoryProvider } from './service/lib';
|
||||
import { NodesVersionCompatibility } from '../elasticsearch/version_check/ensure_es_version';
|
||||
import { SavedObjectsRepository } from './service/lib/repository';
|
||||
import { KibanaRequest } from '../http';
|
||||
|
||||
jest.mock('./service/lib/repository');
|
||||
|
||||
describe('SavedObjectsService', () => {
|
||||
const createCoreContext = ({
|
||||
|
@ -269,5 +273,86 @@ describe('SavedObjectsService', () => {
|
|||
expect(getTypeRegistry()).toBe(typeRegistryInstanceMock);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#createScopedRepository', () => {
|
||||
it('creates a respository scoped to the user', async () => {
|
||||
const coreContext = createCoreContext({ skipMigration: false });
|
||||
const soService = new SavedObjectsService(coreContext);
|
||||
const coreSetup = createSetupDeps();
|
||||
await soService.setup(coreSetup);
|
||||
const { createScopedRepository } = await soService.start({});
|
||||
|
||||
const req = {} as KibanaRequest;
|
||||
createScopedRepository(req);
|
||||
|
||||
expect(coreSetup.elasticsearch.adminClient.asScoped).toHaveBeenCalledWith(req);
|
||||
|
||||
const [
|
||||
{
|
||||
value: { callAsCurrentUser },
|
||||
},
|
||||
] = coreSetup.elasticsearch.adminClient.asScoped.mock.results;
|
||||
|
||||
const [
|
||||
[, , , callCluster, includedHiddenTypes],
|
||||
] = (SavedObjectsRepository.createRepository as jest.Mocked<any>).mock.calls;
|
||||
|
||||
expect(callCluster).toBe(callAsCurrentUser);
|
||||
expect(includedHiddenTypes).toEqual([]);
|
||||
});
|
||||
|
||||
it('creates a respository including hidden types when specified', async () => {
|
||||
const coreContext = createCoreContext({ skipMigration: false });
|
||||
const soService = new SavedObjectsService(coreContext);
|
||||
const coreSetup = createSetupDeps();
|
||||
await soService.setup(coreSetup);
|
||||
const { createScopedRepository } = await soService.start({});
|
||||
|
||||
const req = {} as KibanaRequest;
|
||||
createScopedRepository(req, ['someHiddenType']);
|
||||
|
||||
const [
|
||||
[, , , , includedHiddenTypes],
|
||||
] = (SavedObjectsRepository.createRepository as jest.Mocked<any>).mock.calls;
|
||||
|
||||
expect(includedHiddenTypes).toEqual(['someHiddenType']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#createInternalRepository', () => {
|
||||
it('creates a respository using the admin user', async () => {
|
||||
const coreContext = createCoreContext({ skipMigration: false });
|
||||
const soService = new SavedObjectsService(coreContext);
|
||||
const coreSetup = createSetupDeps();
|
||||
await soService.setup(coreSetup);
|
||||
const { createInternalRepository } = await soService.start({});
|
||||
|
||||
createInternalRepository();
|
||||
|
||||
const [
|
||||
[, , , callCluster, includedHiddenTypes],
|
||||
] = (SavedObjectsRepository.createRepository as jest.Mocked<any>).mock.calls;
|
||||
|
||||
expect(coreSetup.elasticsearch.adminClient.callAsInternalUser).toBe(callCluster);
|
||||
expect(callCluster).toBe(coreSetup.elasticsearch.adminClient.callAsInternalUser);
|
||||
expect(includedHiddenTypes).toEqual([]);
|
||||
});
|
||||
|
||||
it('creates a respository including hidden types when specified', async () => {
|
||||
const coreContext = createCoreContext({ skipMigration: false });
|
||||
const soService = new SavedObjectsService(coreContext);
|
||||
const coreSetup = createSetupDeps();
|
||||
await soService.setup(coreSetup);
|
||||
const { createInternalRepository } = await soService.start({});
|
||||
|
||||
createInternalRepository(['someHiddenType']);
|
||||
|
||||
const [
|
||||
[, , , , includedHiddenTypes],
|
||||
] = (SavedObjectsRepository.createRepository as jest.Mocked<any>).mock.calls;
|
||||
|
||||
expect(includedHiddenTypes).toEqual(['someHiddenType']);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -198,20 +198,23 @@ export interface SavedObjectsServiceStart {
|
|||
* Elasticsearch.
|
||||
*
|
||||
* @param req - The request to create the scoped repository from.
|
||||
* @param extraTypes - A list of additional hidden types the repository should have access to.
|
||||
* @param includedHiddenTypes - A list of additional hidden types the repository should have access to.
|
||||
*
|
||||
* @remarks
|
||||
* Prefer using `getScopedClient`. This should only be used when using methods
|
||||
* not exposed on {@link SavedObjectsClientContract}
|
||||
*/
|
||||
createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (
|
||||
req: KibanaRequest,
|
||||
includedHiddenTypes?: string[]
|
||||
) => ISavedObjectsRepository;
|
||||
/**
|
||||
* Creates a {@link ISavedObjectsRepository | Saved Objects repository} that
|
||||
* uses the internal Kibana user for authenticating with Elasticsearch.
|
||||
*
|
||||
* @param extraTypes - A list of additional hidden types the repository should have access to.
|
||||
* @param includedHiddenTypes - A list of additional hidden types the repository should have access to.
|
||||
*/
|
||||
createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createInternalRepository: (includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
/**
|
||||
* Creates a {@link SavedObjectsSerializer | serializer} that is aware of all registered types.
|
||||
*/
|
||||
|
@ -246,16 +249,19 @@ export interface SavedObjectsRepositoryFactory {
|
|||
* uses the credentials from the passed in request to authenticate with
|
||||
* Elasticsearch.
|
||||
*
|
||||
* @param extraTypes - A list of additional hidden types the repository should have access to.
|
||||
* @param includedHiddenTypes - A list of additional hidden types the repository should have access to.
|
||||
*/
|
||||
createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (
|
||||
req: KibanaRequest,
|
||||
includedHiddenTypes?: string[]
|
||||
) => ISavedObjectsRepository;
|
||||
/**
|
||||
* Creates a {@link ISavedObjectsRepository | Saved Objects repository} that
|
||||
* uses the internal Kibana user for authenticating with Elasticsearch.
|
||||
*
|
||||
* @param extraTypes - A list of additional hidden types the repository should have access to.
|
||||
* @param includedHiddenTypes - A list of additional hidden types the repository should have access to.
|
||||
*/
|
||||
createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createInternalRepository: (includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -417,26 +423,26 @@ export class SavedObjectsService
|
|||
await migrator.runMigrations();
|
||||
}
|
||||
|
||||
const createRepository = (callCluster: APICaller, extraTypes: string[] = []) => {
|
||||
const createRepository = (callCluster: APICaller, includedHiddenTypes: string[] = []) => {
|
||||
return SavedObjectsRepository.createRepository(
|
||||
migrator,
|
||||
this.typeRegistry,
|
||||
kibanaConfig.index,
|
||||
callCluster,
|
||||
extraTypes
|
||||
includedHiddenTypes
|
||||
);
|
||||
};
|
||||
|
||||
const repositoryFactory: SavedObjectsRepositoryFactory = {
|
||||
createInternalRepository: (extraTypes?: string[]) =>
|
||||
createRepository(adminClient.callAsInternalUser, extraTypes),
|
||||
createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) =>
|
||||
createRepository(adminClient.asScoped(req).callAsCurrentUser, extraTypes),
|
||||
createInternalRepository: (includedHiddenTypes?: string[]) =>
|
||||
createRepository(adminClient.callAsInternalUser, includedHiddenTypes),
|
||||
createScopedRepository: (req: KibanaRequest, includedHiddenTypes?: string[]) =>
|
||||
createRepository(adminClient.asScoped(req).callAsCurrentUser, includedHiddenTypes),
|
||||
};
|
||||
|
||||
const clientProvider = new SavedObjectsClientProvider({
|
||||
defaultClientFactory({ request }) {
|
||||
const repository = repositoryFactory.createScopedRepository(request);
|
||||
defaultClientFactory({ request, includedHiddenTypes }) {
|
||||
const repository = repositoryFactory.createScopedRepository(request, includedHiddenTypes);
|
||||
return new SavedObjectsClient(repository);
|
||||
},
|
||||
typeRegistry: this.typeRegistry,
|
||||
|
|
|
@ -131,7 +131,7 @@ export class SavedObjectsRepository {
|
|||
typeRegistry: SavedObjectTypeRegistry,
|
||||
indexName: string,
|
||||
callCluster: APICaller,
|
||||
extraTypes: string[] = [],
|
||||
includedHiddenTypes: string[] = [],
|
||||
injectedConstructor: any = SavedObjectsRepository
|
||||
): ISavedObjectsRepository {
|
||||
const mappings = migrator.getActiveMappings();
|
||||
|
@ -139,14 +139,14 @@ export class SavedObjectsRepository {
|
|||
const serializer = new SavedObjectsSerializer(typeRegistry);
|
||||
const visibleTypes = allTypes.filter(type => !typeRegistry.isHidden(type));
|
||||
|
||||
const missingTypeMappings = extraTypes.filter(type => !allTypes.includes(type));
|
||||
const missingTypeMappings = includedHiddenTypes.filter(type => !allTypes.includes(type));
|
||||
if (missingTypeMappings.length > 0) {
|
||||
throw new Error(
|
||||
`Missing mappings for saved objects types: '${missingTypeMappings.join(', ')}'`
|
||||
);
|
||||
}
|
||||
|
||||
const allowedTypes = [...new Set(visibleTypes.concat(extraTypes))];
|
||||
const allowedTypes = [...new Set(visibleTypes.concat(includedHiddenTypes))];
|
||||
|
||||
return new injectedConstructor({
|
||||
index: indexName,
|
||||
|
|
|
@ -167,3 +167,23 @@ test(`allows all wrappers to be excluded`, () => {
|
|||
expect(firstClientWrapperFactoryMock).not.toHaveBeenCalled();
|
||||
expect(secondClientWrapperFactoryMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test(`allows hidden typed to be included`, () => {
|
||||
const defaultClient = Symbol();
|
||||
const defaultClientFactoryMock = jest.fn().mockReturnValue(defaultClient);
|
||||
const clientProvider = new SavedObjectsClientProvider({
|
||||
defaultClientFactory: defaultClientFactoryMock,
|
||||
typeRegistry: typeRegistryMock.create(),
|
||||
});
|
||||
const request = Symbol();
|
||||
|
||||
const actualClient = clientProvider.getClient(request, {
|
||||
includedHiddenTypes: ['task'],
|
||||
});
|
||||
|
||||
expect(actualClient).toBe(defaultClient);
|
||||
expect(defaultClientFactoryMock).toHaveBeenCalledWith({
|
||||
request,
|
||||
includedHiddenTypes: ['task'],
|
||||
});
|
||||
});
|
||||
|
|
|
@ -46,8 +46,10 @@ export type SavedObjectsClientWrapperFactory = (
|
|||
*/
|
||||
export type SavedObjectsClientFactory = ({
|
||||
request,
|
||||
includedHiddenTypes,
|
||||
}: {
|
||||
request: KibanaRequest;
|
||||
includedHiddenTypes?: string[];
|
||||
}) => SavedObjectsClientContract;
|
||||
|
||||
/**
|
||||
|
@ -64,6 +66,7 @@ export type SavedObjectsClientFactoryProvider = (
|
|||
*/
|
||||
export interface SavedObjectsClientProviderOptions {
|
||||
excludedWrappers?: string[];
|
||||
includedHiddenTypes?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,14 +124,13 @@ export class SavedObjectsClientProvider {
|
|||
|
||||
getClient(
|
||||
request: KibanaRequest,
|
||||
options: SavedObjectsClientProviderOptions = {}
|
||||
{ includedHiddenTypes, excludedWrappers = [] }: SavedObjectsClientProviderOptions = {}
|
||||
): SavedObjectsClientContract {
|
||||
const client = this._clientFactory({
|
||||
request,
|
||||
includedHiddenTypes,
|
||||
});
|
||||
|
||||
const excludedWrappers = options.excludedWrappers || [];
|
||||
|
||||
return this._wrapperFactories
|
||||
.toPrioritizedArray()
|
||||
.reduceRight((clientToWrap, { id, factory }) => {
|
||||
|
|
|
@ -1840,8 +1840,9 @@ export class SavedObjectsClient {
|
|||
export type SavedObjectsClientContract = Pick<SavedObjectsClient, keyof SavedObjectsClient>;
|
||||
|
||||
// @public
|
||||
export type SavedObjectsClientFactory = ({ request, }: {
|
||||
export type SavedObjectsClientFactory = ({ request, includedHiddenTypes, }: {
|
||||
request: KibanaRequest;
|
||||
includedHiddenTypes?: string[];
|
||||
}) => SavedObjectsClientContract;
|
||||
|
||||
// @public
|
||||
|
@ -1851,6 +1852,8 @@ export type SavedObjectsClientFactoryProvider = (repositoryFactory: SavedObjects
|
|||
export interface SavedObjectsClientProviderOptions {
|
||||
// (undocumented)
|
||||
excludedWrappers?: string[];
|
||||
// (undocumented)
|
||||
includedHiddenTypes?: string[];
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -2213,7 +2216,7 @@ export class SavedObjectsRepository {
|
|||
// Warning: (ae-forgotten-export) The symbol "KibanaMigrator" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @internal
|
||||
static createRepository(migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, callCluster: APICaller, extraTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository;
|
||||
static createRepository(migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, callCluster: APICaller, includedHiddenTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository;
|
||||
delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>;
|
||||
deleteByNamespace(namespace: string, options?: SavedObjectsDeleteByNamespaceOptions): Promise<any>;
|
||||
deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise<{}>;
|
||||
|
@ -2233,8 +2236,8 @@ export class SavedObjectsRepository {
|
|||
|
||||
// @public
|
||||
export interface SavedObjectsRepositoryFactory {
|
||||
createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createInternalRepository: (includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (req: KibanaRequest, includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -2285,8 +2288,8 @@ export interface SavedObjectsServiceSetup {
|
|||
|
||||
// @public
|
||||
export interface SavedObjectsServiceStart {
|
||||
createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository;
|
||||
createInternalRepository: (includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
createScopedRepository: (req: KibanaRequest, includedHiddenTypes?: string[]) => ISavedObjectsRepository;
|
||||
createSerializer: () => SavedObjectsSerializer;
|
||||
getScopedClient: (req: KibanaRequest, options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;
|
||||
getTypeRegistry: () => ISavedObjectTypeRegistry;
|
||||
|
|
|
@ -50,17 +50,17 @@ export function savedObjectsMixin(kbnServer, server) {
|
|||
|
||||
const serializer = kbnServer.newPlatform.start.core.savedObjects.createSerializer();
|
||||
|
||||
const createRepository = (callCluster, extraTypes = []) => {
|
||||
const createRepository = (callCluster, includedHiddenTypes = []) => {
|
||||
if (typeof callCluster !== 'function') {
|
||||
throw new TypeError('Repository requires a "callCluster" function to be provided.');
|
||||
}
|
||||
// throw an exception if an extraType is not defined.
|
||||
extraTypes.forEach(type => {
|
||||
includedHiddenTypes.forEach(type => {
|
||||
if (!allTypes.includes(type)) {
|
||||
throw new Error(`Missing mappings for saved objects type '${type}'`);
|
||||
}
|
||||
});
|
||||
const combinedTypes = visibleTypes.concat(extraTypes);
|
||||
const combinedTypes = visibleTypes.concat(includedHiddenTypes);
|
||||
const allowedTypes = [...new Set(combinedTypes)];
|
||||
|
||||
const config = server.config();
|
||||
|
|
|
@ -18,7 +18,7 @@ import { actionsMock } from '../mocks';
|
|||
const actionExecutor = new ActionExecutor({ isESOUsingEphemeralEncryptionKey: false });
|
||||
const services = actionsMock.createServices();
|
||||
const savedObjectsClient = services.savedObjectsClient;
|
||||
const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart();
|
||||
const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient();
|
||||
const actionTypeRegistry = actionTypeRegistryMock.create();
|
||||
|
||||
const executeParams = {
|
||||
|
@ -35,7 +35,7 @@ actionExecutor.initialize({
|
|||
spaces: spacesMock,
|
||||
getServices: () => services,
|
||||
actionTypeRegistry,
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient,
|
||||
eventLogger: eventLoggerMock.create(),
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
|
@ -67,11 +67,11 @@ test('successfully executes', async () => {
|
|||
references: [],
|
||||
};
|
||||
savedObjectsClient.get.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
await actionExecutor.execute(executeParams);
|
||||
|
||||
expect(encryptedSavedObjectsPlugin.getDecryptedAsInternalUser).toHaveBeenCalledWith(
|
||||
expect(encryptedSavedObjectsClient.getDecryptedAsInternalUser).toHaveBeenCalledWith(
|
||||
'action',
|
||||
'1',
|
||||
{ namespace: 'some-namespace' }
|
||||
|
@ -108,7 +108,7 @@ test('provides empty config when config and / or secrets is empty', async () =>
|
|||
references: [],
|
||||
};
|
||||
savedObjectsClient.get.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
await actionExecutor.execute(executeParams);
|
||||
|
||||
|
@ -138,7 +138,7 @@ test('throws an error when config is invalid', async () => {
|
|||
references: [],
|
||||
};
|
||||
savedObjectsClient.get.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
|
||||
const result = await actionExecutor.execute(executeParams);
|
||||
|
@ -171,7 +171,7 @@ test('throws an error when params is invalid', async () => {
|
|||
references: [],
|
||||
};
|
||||
savedObjectsClient.get.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
|
||||
const result = await actionExecutor.execute(executeParams);
|
||||
|
@ -206,7 +206,7 @@ test('throws an error if actionType is not enabled', async () => {
|
|||
references: [],
|
||||
};
|
||||
savedObjectsClient.get.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
actionTypeRegistry.ensureActionTypeEnabled.mockImplementationOnce(() => {
|
||||
throw new Error('not enabled for test');
|
||||
|
@ -240,7 +240,7 @@ test('should not throws an error if actionType is preconfigured', async () => {
|
|||
references: [],
|
||||
};
|
||||
savedObjectsClient.get.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject);
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
actionTypeRegistry.ensureActionTypeEnabled.mockImplementationOnce(() => {
|
||||
throw new Error('not enabled for test');
|
||||
|
@ -269,7 +269,7 @@ test('throws an error when passing isESOUsingEphemeralEncryptionKey with value o
|
|||
spaces: spacesMock,
|
||||
getServices: () => services,
|
||||
actionTypeRegistry,
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient,
|
||||
eventLogger: eventLoggerMock.create(),
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
PreConfiguredAction,
|
||||
Services,
|
||||
} from '../types';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server';
|
||||
import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server';
|
||||
import { SpacesServiceSetup } from '../../../spaces/server';
|
||||
import { EVENT_LOG_ACTIONS } from '../plugin';
|
||||
import { IEvent, IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '../../../event_log/server';
|
||||
|
@ -23,7 +23,7 @@ export interface ActionExecutorContext {
|
|||
logger: Logger;
|
||||
spaces?: SpacesServiceSetup;
|
||||
getServices: GetServicesFunction;
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart;
|
||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
actionTypeRegistry: ActionTypeRegistryContract;
|
||||
eventLogger: IEventLogger;
|
||||
preconfiguredActions: PreConfiguredAction[];
|
||||
|
@ -72,7 +72,7 @@ export class ActionExecutor {
|
|||
const {
|
||||
spaces,
|
||||
getServices,
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient,
|
||||
actionTypeRegistry,
|
||||
eventLogger,
|
||||
preconfiguredActions,
|
||||
|
@ -84,7 +84,7 @@ export class ActionExecutor {
|
|||
|
||||
const { actionTypeId, name, config, secrets } = await getActionInfo(
|
||||
services,
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient,
|
||||
preconfiguredActions,
|
||||
actionId,
|
||||
namespace.namespace
|
||||
|
@ -196,7 +196,7 @@ interface ActionInfo {
|
|||
|
||||
async function getActionInfo(
|
||||
services: Services,
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart,
|
||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient,
|
||||
preconfiguredActions: PreConfiguredAction[],
|
||||
actionId: string,
|
||||
namespace: string | undefined
|
||||
|
@ -222,7 +222,7 @@ async function getActionInfo(
|
|||
|
||||
const {
|
||||
attributes: { secrets },
|
||||
} = await encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<RawAction>('action', actionId, {
|
||||
} = await encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawAction>('action', actionId, {
|
||||
namespace: namespace === 'default' ? undefined : namespace,
|
||||
});
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import { ActionTypeDisabledError } from './errors';
|
|||
|
||||
const spaceIdToNamespace = jest.fn();
|
||||
const actionTypeRegistry = actionTypeRegistryMock.create();
|
||||
const mockedEncryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart();
|
||||
const mockedEncryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient();
|
||||
const mockedActionExecutor = actionExecutorMock.create();
|
||||
|
||||
let fakeTimer: sinon.SinonFakeTimers;
|
||||
|
@ -59,7 +59,7 @@ const actionExecutorInitializerParams = {
|
|||
logger: loggingServiceMock.create().get(),
|
||||
getServices: jest.fn().mockReturnValue(services),
|
||||
actionTypeRegistry,
|
||||
encryptedSavedObjectsPlugin: mockedEncryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient: mockedEncryptedSavedObjectsClient,
|
||||
eventLogger: eventLoggerMock.create(),
|
||||
preconfiguredActions: [],
|
||||
};
|
||||
|
@ -67,7 +67,7 @@ const taskRunnerFactoryInitializerParams = {
|
|||
spaceIdToNamespace,
|
||||
actionTypeRegistry,
|
||||
logger: loggingServiceMock.create().get(),
|
||||
encryptedSavedObjectsPlugin: mockedEncryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient: mockedEncryptedSavedObjectsClient,
|
||||
getBasePath: jest.fn().mockReturnValue(undefined),
|
||||
getScopedSavedObjectsClient: jest.fn().mockReturnValue(services.savedObjectsClient),
|
||||
};
|
||||
|
@ -106,7 +106,7 @@ test('executes the task by calling the executor with proper parameters', async (
|
|||
|
||||
mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' });
|
||||
spaceIdToNamespace.mockReturnValueOnce('namespace-test');
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '3',
|
||||
type: 'action_task_params',
|
||||
attributes: {
|
||||
|
@ -122,7 +122,7 @@ test('executes the task by calling the executor with proper parameters', async (
|
|||
expect(runnerResult).toBeUndefined();
|
||||
expect(spaceIdToNamespace).toHaveBeenCalledWith('test');
|
||||
expect(
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser
|
||||
).toHaveBeenCalledWith('action_task_params', '3', { namespace: 'namespace-test' });
|
||||
expect(mockedActionExecutor.execute).toHaveBeenCalledWith({
|
||||
actionId: '2',
|
||||
|
@ -154,7 +154,7 @@ test('cleans up action_task_params object', async () => {
|
|||
|
||||
mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' });
|
||||
spaceIdToNamespace.mockReturnValueOnce('namespace-test');
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '3',
|
||||
type: 'action_task_params',
|
||||
attributes: {
|
||||
|
@ -177,7 +177,7 @@ test('runs successfully when cleanup fails and logs the error', async () => {
|
|||
|
||||
mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' });
|
||||
spaceIdToNamespace.mockReturnValueOnce('namespace-test');
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '3',
|
||||
type: 'action_task_params',
|
||||
attributes: {
|
||||
|
@ -202,7 +202,7 @@ test('throws an error with suggested retry logic when return status is error', a
|
|||
taskInstance: mockedTaskInstance,
|
||||
});
|
||||
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '3',
|
||||
type: 'action_task_params',
|
||||
attributes: {
|
||||
|
@ -237,7 +237,7 @@ test('uses API key when provided', async () => {
|
|||
|
||||
mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' });
|
||||
spaceIdToNamespace.mockReturnValueOnce('namespace-test');
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '3',
|
||||
type: 'action_task_params',
|
||||
attributes: {
|
||||
|
@ -280,7 +280,7 @@ test(`doesn't use API key when not provided`, async () => {
|
|||
|
||||
mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' });
|
||||
spaceIdToNamespace.mockReturnValueOnce('namespace-test');
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '3',
|
||||
type: 'action_task_params',
|
||||
attributes: {
|
||||
|
@ -317,7 +317,7 @@ test(`throws an error when license doesn't support the action type`, async () =>
|
|||
taskInstance: mockedTaskInstance,
|
||||
});
|
||||
|
||||
mockedEncryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '3',
|
||||
type: 'action_task_params',
|
||||
attributes: {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { ActionExecutorContract } from './action_executor';
|
|||
import { ExecutorError } from './executor_error';
|
||||
import { Logger, CoreStart, KibanaRequest } from '../../../../../src/core/server';
|
||||
import { RunContext } from '../../../task_manager/server';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server';
|
||||
import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server';
|
||||
import { ActionTypeDisabledError } from './errors';
|
||||
import {
|
||||
ActionTaskParams,
|
||||
|
@ -21,7 +21,7 @@ import {
|
|||
export interface TaskRunnerContext {
|
||||
logger: Logger;
|
||||
actionTypeRegistry: ActionTypeRegistryContract;
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart;
|
||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
spaceIdToNamespace: SpaceIdToNamespaceFunction;
|
||||
getBasePath: GetBasePathFunction;
|
||||
getScopedSavedObjectsClient: CoreStart['savedObjects']['getScopedClient'];
|
||||
|
@ -52,7 +52,7 @@ export class TaskRunnerFactory {
|
|||
const { actionExecutor } = this;
|
||||
const {
|
||||
logger,
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient,
|
||||
spaceIdToNamespace,
|
||||
getBasePath,
|
||||
getScopedSavedObjectsClient,
|
||||
|
@ -65,7 +65,7 @@ export class TaskRunnerFactory {
|
|||
|
||||
const {
|
||||
attributes: { actionId, params, apiKey },
|
||||
} = await encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<ActionTaskParams>(
|
||||
} = await encryptedSavedObjectsClient.getDecryptedAsInternalUser<ActionTaskParams>(
|
||||
'action_task_params',
|
||||
actionTaskParamsId,
|
||||
{ namespace }
|
||||
|
|
|
@ -232,12 +232,14 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
|
|||
preconfiguredActions,
|
||||
} = this;
|
||||
|
||||
const encryptedSavedObjectsClient = plugins.encryptedSavedObjects.getClient();
|
||||
|
||||
actionExecutor!.initialize({
|
||||
logger,
|
||||
eventLogger: this.eventLogger!,
|
||||
spaces: this.spaces,
|
||||
getServices: this.getServicesFactory(core.savedObjects, core.elasticsearch),
|
||||
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
|
||||
encryptedSavedObjectsClient,
|
||||
actionTypeRegistry: actionTypeRegistry!,
|
||||
preconfiguredActions,
|
||||
});
|
||||
|
@ -245,7 +247,7 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
|
|||
taskRunnerFactory!.initialize({
|
||||
logger,
|
||||
actionTypeRegistry: actionTypeRegistry!,
|
||||
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
|
||||
encryptedSavedObjectsClient,
|
||||
getBasePath: this.getBasePath,
|
||||
spaceIdToNamespace: this.spaceIdToNamespace,
|
||||
getScopedSavedObjectsClient: core.savedObjects.getScopedClient,
|
||||
|
|
|
@ -17,7 +17,7 @@ import { encryptedSavedObjectsMock } from '../../../plugins/encrypted_saved_obje
|
|||
const taskManager = taskManagerMock.start();
|
||||
const alertTypeRegistry = alertTypeRegistryMock.create();
|
||||
const savedObjectsClient = savedObjectsClientMock.create();
|
||||
const encryptedSavedObjects = encryptedSavedObjectsMock.createStart();
|
||||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
|
||||
const alertsClientParams = {
|
||||
taskManager,
|
||||
|
@ -29,7 +29,7 @@ const alertsClientParams = {
|
|||
createAPIKey: jest.fn(),
|
||||
invalidateAPIKey: jest.fn(),
|
||||
logger: loggingServiceMock.create().get(),
|
||||
encryptedSavedObjectsPlugin: encryptedSavedObjects,
|
||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||
preconfiguredActions: [],
|
||||
};
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import {
|
|||
GrantAPIKeyResult as SecurityPluginGrantAPIKeyResult,
|
||||
InvalidateAPIKeyResult as SecurityPluginInvalidateAPIKeyResult,
|
||||
} from '../../../plugins/security/server';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../plugins/encrypted_saved_objects/server';
|
||||
import { EncryptedSavedObjectsClient } from '../../../plugins/encrypted_saved_objects/server';
|
||||
import { TaskManagerStartContract } from '../../../plugins/task_manager/server';
|
||||
import { taskInstanceToAlertTaskInstance } from './task_runner/alert_task_instance';
|
||||
import { deleteTaskIfItExists } from './lib/delete_task_if_it_exists';
|
||||
|
@ -50,7 +50,7 @@ interface ConstructorOptions {
|
|||
taskManager: TaskManagerStartContract;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
alertTypeRegistry: AlertTypeRegistry;
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart;
|
||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
spaceId?: string;
|
||||
namespace?: string;
|
||||
getUserName: () => Promise<string | null>;
|
||||
|
@ -128,7 +128,7 @@ export class AlertsClient {
|
|||
params: InvalidateAPIKeyParams
|
||||
) => Promise<InvalidateAPIKeyResult>;
|
||||
private preconfiguredActions: PreConfiguredAction[];
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart;
|
||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
|
||||
constructor({
|
||||
alertTypeRegistry,
|
||||
|
@ -140,7 +140,7 @@ export class AlertsClient {
|
|||
getUserName,
|
||||
createAPIKey,
|
||||
invalidateAPIKey,
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient,
|
||||
preconfiguredActions,
|
||||
}: ConstructorOptions) {
|
||||
this.logger = logger;
|
||||
|
@ -152,7 +152,7 @@ export class AlertsClient {
|
|||
this.savedObjectsClient = savedObjectsClient;
|
||||
this.createAPIKey = createAPIKey;
|
||||
this.invalidateAPIKey = invalidateAPIKey;
|
||||
this.encryptedSavedObjectsPlugin = encryptedSavedObjectsPlugin;
|
||||
this.encryptedSavedObjectsClient = encryptedSavedObjectsClient;
|
||||
this.preconfiguredActions = preconfiguredActions;
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ export class AlertsClient {
|
|||
let apiKeyToInvalidate: string | null = null;
|
||||
|
||||
try {
|
||||
const decryptedAlert = await this.encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<
|
||||
const decryptedAlert = await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<
|
||||
RawAlert
|
||||
>('alert', id, { namespace: this.namespace });
|
||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||
|
@ -281,7 +281,7 @@ export class AlertsClient {
|
|||
let alertSavedObject: SavedObject<RawAlert>;
|
||||
|
||||
try {
|
||||
alertSavedObject = await this.encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<
|
||||
alertSavedObject = await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<
|
||||
RawAlert
|
||||
>('alert', id, { namespace: this.namespace });
|
||||
} catch (e) {
|
||||
|
@ -377,7 +377,7 @@ export class AlertsClient {
|
|||
let version: string | undefined;
|
||||
|
||||
try {
|
||||
const decryptedAlert = await this.encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<
|
||||
const decryptedAlert = await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<
|
||||
RawAlert
|
||||
>('alert', id, { namespace: this.namespace });
|
||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||
|
@ -435,7 +435,7 @@ export class AlertsClient {
|
|||
let version: string | undefined;
|
||||
|
||||
try {
|
||||
const decryptedAlert = await this.encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<
|
||||
const decryptedAlert = await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<
|
||||
RawAlert
|
||||
>('alert', id, { namespace: this.namespace });
|
||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||
|
@ -479,7 +479,7 @@ export class AlertsClient {
|
|||
let version: string | undefined;
|
||||
|
||||
try {
|
||||
const decryptedAlert = await this.encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<
|
||||
const decryptedAlert = await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<
|
||||
RawAlert
|
||||
>('alert', id, { namespace: this.namespace });
|
||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||
|
@ -543,7 +543,7 @@ export class AlertsClient {
|
|||
alertId: string;
|
||||
alertInstanceId: string;
|
||||
}) {
|
||||
const { attributes, version } = await this.savedObjectsClient.get('alert', alertId);
|
||||
const { attributes, version } = await this.savedObjectsClient.get<Alert>('alert', alertId);
|
||||
const mutedInstanceIds = attributes.mutedInstanceIds || [];
|
||||
if (!attributes.muteAll && !mutedInstanceIds.includes(alertInstanceId)) {
|
||||
mutedInstanceIds.push(alertInstanceId);
|
||||
|
@ -566,7 +566,7 @@ export class AlertsClient {
|
|||
alertId: string;
|
||||
alertInstanceId: string;
|
||||
}) {
|
||||
const { attributes, version } = await this.savedObjectsClient.get('alert', alertId);
|
||||
const { attributes, version } = await this.savedObjectsClient.get<Alert>('alert', alertId);
|
||||
const mutedInstanceIds = attributes.mutedInstanceIds || [];
|
||||
if (!attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) {
|
||||
await this.savedObjectsClient.update(
|
||||
|
|
|
@ -24,7 +24,7 @@ const alertsClientFactoryParams: jest.Mocked<AlertsClientFactoryOpts> = {
|
|||
alertTypeRegistry: alertTypeRegistryMock.create(),
|
||||
getSpaceId: jest.fn(),
|
||||
spaceIdToNamespace: jest.fn(),
|
||||
encryptedSavedObjectsPlugin: encryptedSavedObjectsMock.createStart(),
|
||||
encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(),
|
||||
preconfiguredActions: [],
|
||||
};
|
||||
const fakeRequest = ({
|
||||
|
@ -64,7 +64,7 @@ test('creates an alerts client with proper constructor arguments', async () => {
|
|||
getUserName: expect.any(Function),
|
||||
createAPIKey: expect.any(Function),
|
||||
invalidateAPIKey: expect.any(Function),
|
||||
encryptedSavedObjectsPlugin: alertsClientFactoryParams.encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient: alertsClientFactoryParams.encryptedSavedObjectsClient,
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import { AlertsClient } from './alerts_client';
|
|||
import { AlertTypeRegistry, SpaceIdToNamespaceFunction } from './types';
|
||||
import { KibanaRequest, Logger, SavedObjectsClientContract } from '../../../../src/core/server';
|
||||
import { InvalidateAPIKeyParams, SecurityPluginSetup } from '../../../plugins/security/server';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../plugins/encrypted_saved_objects/server';
|
||||
import { EncryptedSavedObjectsClient } from '../../../plugins/encrypted_saved_objects/server';
|
||||
import { TaskManagerStartContract } from '../../../plugins/task_manager/server';
|
||||
|
||||
export interface AlertsClientFactoryOpts {
|
||||
|
@ -19,7 +19,7 @@ export interface AlertsClientFactoryOpts {
|
|||
securityPluginSetup?: SecurityPluginSetup;
|
||||
getSpaceId: (request: KibanaRequest) => string | undefined;
|
||||
spaceIdToNamespace: SpaceIdToNamespaceFunction;
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart;
|
||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
preconfiguredActions: PreConfiguredAction[];
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ export class AlertsClientFactory {
|
|||
private securityPluginSetup?: SecurityPluginSetup;
|
||||
private getSpaceId!: (request: KibanaRequest) => string | undefined;
|
||||
private spaceIdToNamespace!: SpaceIdToNamespaceFunction;
|
||||
private encryptedSavedObjectsPlugin!: EncryptedSavedObjectsPluginStart;
|
||||
private encryptedSavedObjectsClient!: EncryptedSavedObjectsClient;
|
||||
private preconfiguredActions!: PreConfiguredAction[];
|
||||
|
||||
public initialize(options: AlertsClientFactoryOpts) {
|
||||
|
@ -45,7 +45,7 @@ export class AlertsClientFactory {
|
|||
this.alertTypeRegistry = options.alertTypeRegistry;
|
||||
this.securityPluginSetup = options.securityPluginSetup;
|
||||
this.spaceIdToNamespace = options.spaceIdToNamespace;
|
||||
this.encryptedSavedObjectsPlugin = options.encryptedSavedObjectsPlugin;
|
||||
this.encryptedSavedObjectsClient = options.encryptedSavedObjectsClient;
|
||||
this.preconfiguredActions = options.preconfiguredActions;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ export class AlertsClientFactory {
|
|||
alertTypeRegistry: this.alertTypeRegistry,
|
||||
savedObjectsClient,
|
||||
namespace: this.spaceIdToNamespace(spaceId),
|
||||
encryptedSavedObjectsPlugin: this.encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient: this.encryptedSavedObjectsClient,
|
||||
async getUserName() {
|
||||
if (!securityPluginSetup) {
|
||||
return null;
|
||||
|
|
|
@ -81,6 +81,7 @@ describe('Alerting Plugin', () => {
|
|||
execute: jest.fn(),
|
||||
getActionsClientWithRequest: jest.fn(),
|
||||
},
|
||||
encryptedSavedObjects: encryptedSavedObjectsMock.createStart(),
|
||||
} as unknown) as AlertingPluginsStart
|
||||
);
|
||||
|
||||
|
@ -125,6 +126,7 @@ describe('Alerting Plugin', () => {
|
|||
getActionsClientWithRequest: jest.fn(),
|
||||
},
|
||||
spaces: () => null,
|
||||
encryptedSavedObjects: encryptedSavedObjectsMock.createStart(),
|
||||
} as unknown) as AlertingPluginsStart
|
||||
);
|
||||
|
||||
|
|
|
@ -201,12 +201,14 @@ export class AlertingPlugin {
|
|||
security,
|
||||
} = this;
|
||||
|
||||
const encryptedSavedObjectsClient = plugins.encryptedSavedObjects.getClient();
|
||||
|
||||
alertsClientFactory.initialize({
|
||||
alertTypeRegistry: alertTypeRegistry!,
|
||||
logger,
|
||||
taskManager: plugins.taskManager,
|
||||
securityPluginSetup: security,
|
||||
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
|
||||
encryptedSavedObjectsClient,
|
||||
spaceIdToNamespace: this.spaceIdToNamespace,
|
||||
getSpaceId(request: KibanaRequest) {
|
||||
return spaces?.getSpaceId(request);
|
||||
|
@ -219,7 +221,7 @@ export class AlertingPlugin {
|
|||
getServices: this.getServicesFactory(core.savedObjects, core.elasticsearch),
|
||||
spaceIdToNamespace: this.spaceIdToNamespace,
|
||||
actionsPlugin: plugins.actions,
|
||||
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
|
||||
encryptedSavedObjectsClient,
|
||||
getBasePath: this.getBasePath,
|
||||
eventLogger: this.eventLogger!,
|
||||
});
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('Task Runner', () => {
|
|||
|
||||
afterAll(() => fakeTimer.restore());
|
||||
|
||||
const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart();
|
||||
const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient();
|
||||
const services = alertsMock.createAlertServices();
|
||||
const savedObjectsClient = services.savedObjectsClient;
|
||||
|
||||
|
@ -64,7 +64,7 @@ describe('Task Runner', () => {
|
|||
} = {
|
||||
getServices: jest.fn().mockReturnValue(services),
|
||||
actionsPlugin: actionsMock.createStart(),
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient,
|
||||
logger: loggingServiceMock.create().get(),
|
||||
spaceIdToNamespace: jest.fn().mockReturnValue(undefined),
|
||||
getBasePath: jest.fn().mockReturnValue(undefined),
|
||||
|
@ -123,7 +123,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -197,7 +197,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -316,7 +316,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -403,7 +403,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -434,7 +434,7 @@ describe('Task Runner', () => {
|
|||
...mockedAlertTypeSavedObject,
|
||||
references: [],
|
||||
});
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -462,7 +462,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -498,7 +498,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {},
|
||||
|
@ -537,7 +537,7 @@ describe('Task Runner', () => {
|
|||
);
|
||||
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -588,7 +588,7 @@ describe('Task Runner', () => {
|
|||
});
|
||||
|
||||
test('recovers gracefully when the Alert Task Runner throws an exception when fetching the encrypted attributes', async () => {
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockImplementation(() => {
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockImplementation(() => {
|
||||
throw new Error('OMG');
|
||||
});
|
||||
|
||||
|
@ -624,7 +624,7 @@ describe('Task Runner', () => {
|
|||
);
|
||||
|
||||
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -656,7 +656,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
@ -688,7 +688,7 @@ describe('Task Runner', () => {
|
|||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
|
||||
encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
|
|
|
@ -62,7 +62,7 @@ export class TaskRunner {
|
|||
// scoped with the API key to fetch the remaining data.
|
||||
const {
|
||||
attributes: { apiKey },
|
||||
} = await this.context.encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<RawAlert>(
|
||||
} = await this.context.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawAlert>(
|
||||
'alert',
|
||||
alertId,
|
||||
{ namespace }
|
||||
|
|
|
@ -56,7 +56,7 @@ describe('Task Runner Factory', () => {
|
|||
const taskRunnerFactoryInitializerParams: jest.Mocked<TaskRunnerContext> = {
|
||||
getServices: jest.fn().mockReturnValue(services),
|
||||
actionsPlugin: actionsMock.createStart(),
|
||||
encryptedSavedObjectsPlugin,
|
||||
encryptedSavedObjectsClient: encryptedSavedObjectsPlugin.getClient(),
|
||||
logger: loggingServiceMock.create().get(),
|
||||
spaceIdToNamespace: jest.fn().mockReturnValue(undefined),
|
||||
getBasePath: jest.fn().mockReturnValue(undefined),
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
import { Logger } from '../../../../../src/core/server';
|
||||
import { RunContext } from '../../../../plugins/task_manager/server';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../../plugins/encrypted_saved_objects/server';
|
||||
import { EncryptedSavedObjectsClient } from '../../../../plugins/encrypted_saved_objects/server';
|
||||
import { PluginStartContract as ActionsPluginStartContract } from '../../../../plugins/actions/server';
|
||||
import {
|
||||
AlertType,
|
||||
|
@ -21,7 +21,7 @@ export interface TaskRunnerContext {
|
|||
getServices: GetServicesFunction;
|
||||
actionsPlugin: ActionsPluginStartContract;
|
||||
eventLogger: IEventLogger;
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart;
|
||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||
spaceIdToNamespace: SpaceIdToNamespaceFunction;
|
||||
getBasePath: GetBasePathFunction;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { Plugin } from './plugin';
|
|||
|
||||
export { EncryptedSavedObjectTypeRegistration, EncryptionError } from './crypto';
|
||||
export { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } from './plugin';
|
||||
export { EncryptedSavedObjectsClient } from './saved_objects';
|
||||
|
||||
export const config = { schema: ConfigSchema };
|
||||
export const plugin = (initializerContext: PluginInitializerContext) =>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } from './plugin';
|
||||
import { EncryptedSavedObjectsClient } from './saved_objects';
|
||||
|
||||
function createEncryptedSavedObjectsSetupMock() {
|
||||
return {
|
||||
|
@ -17,11 +18,18 @@ function createEncryptedSavedObjectsSetupMock() {
|
|||
function createEncryptedSavedObjectsStartMock() {
|
||||
return {
|
||||
isEncryptionError: jest.fn(),
|
||||
getDecryptedAsInternalUser: jest.fn(),
|
||||
getClient: jest.fn(() => createEncryptedSavedObjectsClienttMock()),
|
||||
} as jest.Mocked<EncryptedSavedObjectsPluginStart>;
|
||||
}
|
||||
|
||||
function createEncryptedSavedObjectsClienttMock() {
|
||||
return {
|
||||
getDecryptedAsInternalUser: jest.fn(),
|
||||
} as jest.Mocked<EncryptedSavedObjectsClient>;
|
||||
}
|
||||
|
||||
export const encryptedSavedObjectsMock = {
|
||||
createSetup: createEncryptedSavedObjectsSetupMock,
|
||||
createStart: createEncryptedSavedObjectsStartMock,
|
||||
createClient: createEncryptedSavedObjectsClienttMock,
|
||||
};
|
||||
|
|
|
@ -30,10 +30,18 @@ describe('EncryptedSavedObjects Plugin', () => {
|
|||
it('exposes proper contract', async () => {
|
||||
const plugin = new Plugin(coreMock.createPluginInitializerContext());
|
||||
await plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() });
|
||||
await expect(plugin.start()).toMatchInlineSnapshot(`
|
||||
|
||||
const startContract = plugin.start();
|
||||
await expect(startContract).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"getClient": [Function],
|
||||
"isEncryptionError": [Function],
|
||||
}
|
||||
`);
|
||||
|
||||
expect(startContract.getClient()).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"getDecryptedAsInternalUser": [Function],
|
||||
"isEncryptionError": [Function],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -4,12 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Logger,
|
||||
SavedObjectsBaseOptions,
|
||||
PluginInitializerContext,
|
||||
CoreSetup,
|
||||
} from 'src/core/server';
|
||||
import { Logger, PluginInitializerContext, CoreSetup } from 'src/core/server';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { SecurityPluginSetup } from '../../security/server';
|
||||
import { createConfig$ } from './config';
|
||||
|
@ -31,8 +26,9 @@ export interface EncryptedSavedObjectsPluginSetup {
|
|||
usingEphemeralEncryptionKey: boolean;
|
||||
}
|
||||
|
||||
export interface EncryptedSavedObjectsPluginStart extends SavedObjectsSetup {
|
||||
export interface EncryptedSavedObjectsPluginStart {
|
||||
isEncryptionError: (error: Error) => boolean;
|
||||
getClient: SavedObjectsSetup;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,12 +93,9 @@ export class Plugin {
|
|||
|
||||
public start() {
|
||||
this.logger.debug('Starting plugin');
|
||||
|
||||
return {
|
||||
isEncryptionError: (error: Error) => error instanceof EncryptionError,
|
||||
getDecryptedAsInternalUser: (type: string, id: string, options?: SavedObjectsBaseOptions) => {
|
||||
return this.savedObjectsSetup.getDecryptedAsInternalUser(type, id, options);
|
||||
},
|
||||
getClient: (includedHiddenTypes?: string[]) => this.savedObjectsSetup(includedHiddenTypes),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,13 @@ import { EncryptedSavedObjectsService } from '../crypto';
|
|||
|
||||
describe('#setupSavedObjects', () => {
|
||||
let setupContract: SavedObjectsSetup;
|
||||
let coreStartMock: ReturnType<typeof coreMock.createStart>;
|
||||
let coreSetupMock: ReturnType<typeof coreMock.createSetup>;
|
||||
let mockSavedObjectsRepository: jest.Mocked<ISavedObjectsRepository>;
|
||||
let mockSavedObjectTypeRegistry: jest.Mocked<ISavedObjectTypeRegistry>;
|
||||
let mockEncryptedSavedObjectsService: jest.Mocked<EncryptedSavedObjectsService>;
|
||||
beforeEach(() => {
|
||||
const coreStartMock = coreMock.createStart();
|
||||
coreStartMock = coreMock.createStart();
|
||||
|
||||
mockSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||
coreStartMock.savedObjects.createInternalRepository.mockReturnValue(mockSavedObjectsRepository);
|
||||
|
@ -70,6 +71,33 @@ describe('#setupSavedObjects', () => {
|
|||
).toBeInstanceOf(EncryptedSavedObjectsClientWrapper);
|
||||
});
|
||||
|
||||
it('properly registers client wrapper factory with', () => {
|
||||
expect(coreSetupMock.savedObjects.addClientWrapper).toHaveBeenCalledTimes(1);
|
||||
expect(coreSetupMock.savedObjects.addClientWrapper).toHaveBeenCalledWith(
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
'encryptedSavedObjects',
|
||||
expect.any(Function)
|
||||
);
|
||||
|
||||
const [[, , clientFactory]] = coreSetupMock.savedObjects.addClientWrapper.mock.calls;
|
||||
expect(
|
||||
clientFactory({
|
||||
client: savedObjectsClientMock.create(),
|
||||
typeRegistry: savedObjectsTypeRegistryMock.create(),
|
||||
request: httpServerMock.createKibanaRequest(),
|
||||
})
|
||||
).toBeInstanceOf(EncryptedSavedObjectsClientWrapper);
|
||||
});
|
||||
|
||||
describe('#setupContract', () => {
|
||||
it('includes hiddenTypes when specified', async () => {
|
||||
await setupContract(['hiddenType']);
|
||||
expect(coreStartMock.savedObjects.createInternalRepository).toHaveBeenCalledWith([
|
||||
'hiddenType',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getDecryptedAsInternalUser', () => {
|
||||
it('includes `namespace` for single-namespace saved objects', async () => {
|
||||
const mockSavedObject: SavedObject = {
|
||||
|
@ -82,7 +110,7 @@ describe('#setupSavedObjects', () => {
|
|||
mockSavedObjectTypeRegistry.isSingleNamespace.mockReturnValue(true);
|
||||
|
||||
await expect(
|
||||
setupContract.getDecryptedAsInternalUser(mockSavedObject.type, mockSavedObject.id, {
|
||||
setupContract().getDecryptedAsInternalUser(mockSavedObject.type, mockSavedObject.id, {
|
||||
namespace: 'some-ns',
|
||||
})
|
||||
).resolves.toEqual({
|
||||
|
@ -115,7 +143,7 @@ describe('#setupSavedObjects', () => {
|
|||
mockSavedObjectTypeRegistry.isSingleNamespace.mockReturnValue(false);
|
||||
|
||||
await expect(
|
||||
setupContract.getDecryptedAsInternalUser(mockSavedObject.type, mockSavedObject.id, {
|
||||
setupContract().getDecryptedAsInternalUser(mockSavedObject.type, mockSavedObject.id, {
|
||||
namespace: 'some-ns',
|
||||
})
|
||||
).resolves.toEqual({
|
||||
|
|
|
@ -23,7 +23,9 @@ interface SetupSavedObjectsParams {
|
|||
getStartServices: StartServicesAccessor;
|
||||
}
|
||||
|
||||
export interface SavedObjectsSetup {
|
||||
export type SavedObjectsSetup = (includedHiddenTypes?: string[]) => EncryptedSavedObjectsClient;
|
||||
|
||||
export interface EncryptedSavedObjectsClient {
|
||||
getDecryptedAsInternalUser: <T = unknown>(
|
||||
type: string,
|
||||
id: string,
|
||||
|
@ -54,33 +56,34 @@ export function setupSavedObjects({
|
|||
})
|
||||
);
|
||||
|
||||
const internalRepositoryAndTypeRegistryPromise = getStartServices().then(
|
||||
([core]) =>
|
||||
[core.savedObjects.createInternalRepository(), core.savedObjects.getTypeRegistry()] as [
|
||||
ISavedObjectsRepository,
|
||||
ISavedObjectTypeRegistry
|
||||
]
|
||||
);
|
||||
|
||||
return {
|
||||
getDecryptedAsInternalUser: async <T = unknown>(
|
||||
type: string,
|
||||
id: string,
|
||||
options?: SavedObjectsBaseOptions
|
||||
): Promise<SavedObject<T>> => {
|
||||
const [internalRepository, typeRegistry] = await internalRepositoryAndTypeRegistryPromise;
|
||||
const savedObject = await internalRepository.get(type, id, options);
|
||||
return {
|
||||
...savedObject,
|
||||
attributes: (await service.decryptAttributes(
|
||||
{
|
||||
type,
|
||||
id,
|
||||
namespace: typeRegistry.isSingleNamespace(type) ? options?.namespace : undefined,
|
||||
},
|
||||
savedObject.attributes as Record<string, unknown>
|
||||
)) as T,
|
||||
};
|
||||
},
|
||||
return (includedHiddenTypes?: string[]) => {
|
||||
const internalRepositoryAndTypeRegistryPromise = getStartServices().then(
|
||||
([core]) =>
|
||||
[
|
||||
core.savedObjects.createInternalRepository(includedHiddenTypes),
|
||||
core.savedObjects.getTypeRegistry(),
|
||||
] as [ISavedObjectsRepository, ISavedObjectTypeRegistry]
|
||||
);
|
||||
return {
|
||||
getDecryptedAsInternalUser: async <T = unknown>(
|
||||
type: string,
|
||||
id: string,
|
||||
options?: SavedObjectsBaseOptions
|
||||
): Promise<SavedObject<T>> => {
|
||||
const [internalRepository, typeRegistry] = await internalRepositoryAndTypeRegistryPromise;
|
||||
const savedObject = await internalRepository.get(type, id, options);
|
||||
return {
|
||||
...savedObject,
|
||||
attributes: (await service.decryptAttributes(
|
||||
{
|
||||
type,
|
||||
id,
|
||||
namespace: typeRegistry.isSingleNamespace(type) ? options?.namespace : undefined,
|
||||
},
|
||||
savedObject.attributes as Record<string, unknown>
|
||||
)) as T,
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,11 +22,15 @@ import { IngestManagerAppContext } from '../../plugin';
|
|||
describe('test agent acks services', () => {
|
||||
it('should succeed on valid and matched actions', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
const mockStartEncryptedSOClient = encryptedSavedObjectsMock.createStart();
|
||||
const mockStartEncryptedSOPlugin = encryptedSavedObjectsMock.createStart();
|
||||
appContextService.start(({
|
||||
encryptedSavedObjects: mockStartEncryptedSOClient,
|
||||
encryptedSavedObjects: mockStartEncryptedSOPlugin,
|
||||
} as unknown) as IngestManagerAppContext);
|
||||
|
||||
const [
|
||||
{ value: mockStartEncryptedSOClient },
|
||||
] = mockStartEncryptedSOPlugin.getClient.mock.results;
|
||||
|
||||
mockStartEncryptedSOClient.getDecryptedAsInternalUser.mockReturnValue(
|
||||
Promise.resolve({
|
||||
id: 'action1',
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { SavedObjectsServiceStart, HttpServiceSetup, Logger } from 'src/core/server';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server';
|
||||
import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server';
|
||||
import { SecurityPluginSetup } from '../../../security/server';
|
||||
import { IngestManagerConfigType } from '../../common';
|
||||
import { IngestManagerAppContext } from '../plugin';
|
||||
import { CloudSetup } from '../../../cloud/server';
|
||||
|
||||
class AppContextService {
|
||||
private encryptedSavedObjects: EncryptedSavedObjectsPluginStart | undefined;
|
||||
private encryptedSavedObjects: EncryptedSavedObjectsClient | undefined;
|
||||
private security: SecurityPluginSetup | undefined;
|
||||
private config$?: Observable<IngestManagerConfigType>;
|
||||
private configSubject$?: BehaviorSubject<IngestManagerConfigType>;
|
||||
|
@ -25,7 +25,7 @@ class AppContextService {
|
|||
private httpSetup?: HttpServiceSetup;
|
||||
|
||||
public async start(appContext: IngestManagerAppContext) {
|
||||
this.encryptedSavedObjects = appContext.encryptedSavedObjects;
|
||||
this.encryptedSavedObjects = appContext.encryptedSavedObjects?.getClient();
|
||||
this.security = appContext.security;
|
||||
this.savedObjects = appContext.savedObjects;
|
||||
this.isProductionMode = appContext.isProductionMode;
|
||||
|
|
|
@ -31,12 +31,12 @@ export function setupSavedObjects({
|
|||
const getKibanaRequest = (request: KibanaRequest | LegacyRequest) =>
|
||||
request instanceof KibanaRequest ? request : KibanaRequest.from(request);
|
||||
|
||||
savedObjects.setClientFactoryProvider(repositoryFactory => ({ request }) => {
|
||||
savedObjects.setClientFactoryProvider(repositoryFactory => ({ request, includedHiddenTypes }) => {
|
||||
const kibanaRequest = getKibanaRequest(request);
|
||||
return new SavedObjectsClient(
|
||||
authz.mode.useRbacForRequest(kibanaRequest)
|
||||
? repositoryFactory.createInternalRepository()
|
||||
: repositoryFactory.createScopedRepository(kibanaRequest)
|
||||
? repositoryFactory.createInternalRepository(includedHiddenTypes)
|
||||
: repositoryFactory.createScopedRepository(kibanaRequest, includedHiddenTypes)
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -48,9 +48,11 @@ export class FixturePlugin implements Plugin<void, void, FixtureSetupDeps, Fixtu
|
|||
if (spaces && req.body.spaceId) {
|
||||
namespace = spaces.spacesService.spaceIdToNamespace(req.body.spaceId);
|
||||
}
|
||||
await encryptedSavedObjects.getDecryptedAsInternalUser(req.body.type, req.body.id, {
|
||||
namespace,
|
||||
});
|
||||
await encryptedSavedObjects
|
||||
.getClient()
|
||||
.getDecryptedAsInternalUser(req.body.type, req.body.id, {
|
||||
namespace,
|
||||
});
|
||||
return res.ok({ body: { success: true } });
|
||||
} catch (err) {
|
||||
return res.internalError({ body: err });
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* 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 { schema } from '@kbn/config-schema';
|
||||
import { IRouter, CoreSetup } from 'kibana/server';
|
||||
import { PluginsSetup, PluginsStart } from '.';
|
||||
|
||||
export function registerHiddenSORoutes(
|
||||
router: IRouter,
|
||||
core: CoreSetup<PluginsStart>,
|
||||
deps: PluginsSetup,
|
||||
hiddenTypes: string[]
|
||||
) {
|
||||
router.get(
|
||||
{
|
||||
path: '/api/hidden_saved_objects/get-decrypted-as-internal-user/{type}/{id}',
|
||||
validate: { params: value => ({ value }) },
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const [, { encryptedSavedObjects }] = await core.getStartServices();
|
||||
const spaceId = deps.spaces.spacesService.getSpaceId(request);
|
||||
const namespace = deps.spaces.spacesService.spaceIdToNamespace(spaceId);
|
||||
try {
|
||||
return response.ok({
|
||||
body: await encryptedSavedObjects
|
||||
.getClient([request.params.type])
|
||||
.getDecryptedAsInternalUser(request.params.type, request.params.id, { namespace }),
|
||||
});
|
||||
} catch (err) {
|
||||
if (encryptedSavedObjects.isEncryptionError(err)) {
|
||||
return response.badRequest({ body: 'Failed to encrypt attributes' });
|
||||
}
|
||||
|
||||
return response.customError({ body: err, statusCode: 500 });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
{
|
||||
path: '/api/hidden_saved_objects/_find',
|
||||
validate: {
|
||||
query: schema.object({
|
||||
per_page: schema.number({ min: 0, defaultValue: 20 }),
|
||||
page: schema.number({ min: 0, defaultValue: 1 }),
|
||||
type: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]),
|
||||
search: schema.maybe(schema.string()),
|
||||
default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], {
|
||||
defaultValue: 'OR',
|
||||
}),
|
||||
search_fields: schema.maybe(
|
||||
schema.oneOf([schema.string(), schema.arrayOf(schema.string())])
|
||||
),
|
||||
sort_field: schema.maybe(schema.string()),
|
||||
has_reference: schema.maybe(
|
||||
schema.object({
|
||||
type: schema.string(),
|
||||
id: schema.string(),
|
||||
})
|
||||
),
|
||||
fields: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),
|
||||
filter: schema.maybe(schema.string()),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const query = request.query;
|
||||
const [{ savedObjects }] = await core.getStartServices();
|
||||
return response.ok({
|
||||
body: await savedObjects
|
||||
.getScopedClient(request, { includedHiddenTypes: hiddenTypes })
|
||||
.find({
|
||||
perPage: query.per_page,
|
||||
page: query.page,
|
||||
type: Array.isArray(query.type) ? query.type : [query.type],
|
||||
search: query.search,
|
||||
defaultSearchOperator: query.default_search_operator,
|
||||
searchFields:
|
||||
typeof query.search_fields === 'string' ? [query.search_fields] : query.search_fields,
|
||||
sortField: query.sort_field,
|
||||
hasReference: query.has_reference,
|
||||
fields: typeof query.fields === 'string' ? [query.fields] : query.fields,
|
||||
filter: query.filter,
|
||||
}),
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
{
|
||||
path: '/api/hidden_saved_objects/{type}/{id}',
|
||||
validate: { params: value => ({ value }) },
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const [{ savedObjects }] = await core.getStartServices();
|
||||
return response.ok({
|
||||
body: await savedObjects
|
||||
.getScopedClient(request, { includedHiddenTypes: hiddenTypes })
|
||||
.get(request.params.type, request.params.id),
|
||||
});
|
||||
}
|
||||
);
|
||||
router.post(
|
||||
{
|
||||
path: '/api/hidden_saved_objects/{type}',
|
||||
validate: {
|
||||
params: schema.object({
|
||||
type: schema.string(),
|
||||
id: schema.maybe(schema.string()),
|
||||
}),
|
||||
query: schema.object({
|
||||
overwrite: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
body: schema.object({
|
||||
attributes: schema.recordOf(schema.string(), schema.any()),
|
||||
migrationVersion: schema.maybe(schema.recordOf(schema.string(), schema.string())),
|
||||
references: schema.maybe(
|
||||
schema.arrayOf(
|
||||
schema.object({
|
||||
name: schema.string(),
|
||||
type: schema.string(),
|
||||
id: schema.string(),
|
||||
})
|
||||
)
|
||||
),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const [{ savedObjects }] = await core.getStartServices();
|
||||
const { type, id } = request.params;
|
||||
const { attributes, migrationVersion, references } = request.body as any;
|
||||
const options = { id, migrationVersion, references };
|
||||
const so = await savedObjects
|
||||
.getScopedClient(request, { includedHiddenTypes: hiddenTypes })
|
||||
.create(type, attributes, options);
|
||||
return response.ok({
|
||||
body: so,
|
||||
});
|
||||
}
|
||||
);
|
||||
router.put(
|
||||
{
|
||||
path: '/api/hidden_saved_objects/{type}/{id}',
|
||||
validate: {
|
||||
params: schema.object({
|
||||
type: schema.string(),
|
||||
id: schema.string(),
|
||||
}),
|
||||
body: schema.object({
|
||||
attributes: schema.recordOf(schema.string(), schema.any()),
|
||||
version: schema.maybe(schema.string()),
|
||||
references: schema.maybe(
|
||||
schema.arrayOf(
|
||||
schema.object({
|
||||
name: schema.string(),
|
||||
type: schema.string(),
|
||||
id: schema.string(),
|
||||
})
|
||||
)
|
||||
),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const [{ savedObjects }] = await core.getStartServices();
|
||||
const { type, id } = request.params as any;
|
||||
const { attributes, version, references } = request.body as any;
|
||||
const options = { version, references };
|
||||
return response.ok({
|
||||
body: await savedObjects
|
||||
.getScopedClient(request, { includedHiddenTypes: hiddenTypes })
|
||||
.update(type, id, attributes, options),
|
||||
});
|
||||
}
|
||||
);
|
||||
router.post(
|
||||
{
|
||||
path: '/api/hidden_saved_objects/_bulk_get',
|
||||
validate: {
|
||||
body: schema.arrayOf(
|
||||
schema.object({
|
||||
type: schema.string(),
|
||||
id: schema.string(),
|
||||
fields: schema.maybe(schema.arrayOf(schema.string())),
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const [{ savedObjects }] = await core.getStartServices();
|
||||
return response.ok({
|
||||
body: await savedObjects
|
||||
.getScopedClient(request, { includedHiddenTypes: hiddenTypes })
|
||||
.bulkGet(request.body as any),
|
||||
});
|
||||
}
|
||||
);
|
||||
router.post(
|
||||
{
|
||||
path: '/api/hidden_saved_objects/_bulk_create',
|
||||
validate: {
|
||||
body: schema.arrayOf(
|
||||
schema.object({
|
||||
type: schema.string(),
|
||||
id: schema.maybe(schema.string()),
|
||||
attributes: schema.recordOf(schema.string(), schema.any()),
|
||||
version: schema.maybe(schema.string()),
|
||||
migrationVersion: schema.maybe(schema.recordOf(schema.string(), schema.string())),
|
||||
references: schema.maybe(
|
||||
schema.arrayOf(
|
||||
schema.object({
|
||||
name: schema.string(),
|
||||
type: schema.string(),
|
||||
id: schema.string(),
|
||||
})
|
||||
)
|
||||
),
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const [{ savedObjects }] = await core.getStartServices();
|
||||
return response.ok({
|
||||
body: await savedObjects
|
||||
.getScopedClient(request, { includedHiddenTypes: hiddenTypes })
|
||||
.bulkCreate(request.body as any),
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
|
@ -15,31 +15,34 @@ import {
|
|||
EncryptedSavedObjectsPluginStart,
|
||||
} from '../../../../../plugins/encrypted_saved_objects/server';
|
||||
import { SpacesPluginSetup } from '../../../../../plugins/spaces/server';
|
||||
import { registerHiddenSORoutes } from './hidden_saved_object_routes';
|
||||
|
||||
const SAVED_OBJECT_WITH_SECRET_TYPE = 'saved-object-with-secret';
|
||||
const HIDDEN_SAVED_OBJECT_WITH_SECRET_TYPE = 'hidden-saved-object-with-secret';
|
||||
const SAVED_OBJECT_WITH_SECRET_AND_MULTIPLE_SPACES_TYPE =
|
||||
'saved-object-with-secret-and-multiple-spaces';
|
||||
const SAVED_OBJECT_WITHOUT_SECRET_TYPE = 'saved-object-without-secret';
|
||||
|
||||
interface PluginsSetup {
|
||||
export interface PluginsSetup {
|
||||
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup;
|
||||
spaces: SpacesPluginSetup;
|
||||
}
|
||||
|
||||
interface PluginsStart {
|
||||
export interface PluginsStart {
|
||||
encryptedSavedObjects: EncryptedSavedObjectsPluginStart;
|
||||
spaces: never;
|
||||
}
|
||||
|
||||
export const plugin: PluginInitializer<void, void, PluginsSetup, PluginsStart> = () => ({
|
||||
setup(core: CoreSetup<PluginsStart>, deps) {
|
||||
for (const [name, namespaceType] of [
|
||||
[SAVED_OBJECT_WITH_SECRET_TYPE, 'single'],
|
||||
[SAVED_OBJECT_WITH_SECRET_AND_MULTIPLE_SPACES_TYPE, 'multiple'],
|
||||
] as Array<[string, SavedObjectsNamespaceType]>) {
|
||||
for (const [name, namespaceType, hidden] of [
|
||||
[SAVED_OBJECT_WITH_SECRET_TYPE, 'single', false],
|
||||
[HIDDEN_SAVED_OBJECT_WITH_SECRET_TYPE, 'single', true],
|
||||
[SAVED_OBJECT_WITH_SECRET_AND_MULTIPLE_SPACES_TYPE, 'multiple', false],
|
||||
] as Array<[string, SavedObjectsNamespaceType, boolean]>) {
|
||||
core.savedObjects.registerType({
|
||||
name,
|
||||
hidden: false,
|
||||
hidden,
|
||||
namespaceType,
|
||||
mappings: deepFreeze({
|
||||
properties: {
|
||||
|
@ -68,7 +71,8 @@ export const plugin: PluginInitializer<void, void, PluginsSetup, PluginsStart> =
|
|||
mappings: deepFreeze({ properties: { publicProperty: { type: 'keyword' } } }),
|
||||
});
|
||||
|
||||
core.http.createRouter().get(
|
||||
const router = core.http.createRouter();
|
||||
router.get(
|
||||
{
|
||||
path: '/api/saved_objects/get-decrypted-as-internal-user/{type}/{id}',
|
||||
validate: { params: value => ({ value }) },
|
||||
|
@ -80,11 +84,9 @@ export const plugin: PluginInitializer<void, void, PluginsSetup, PluginsStart> =
|
|||
|
||||
try {
|
||||
return response.ok({
|
||||
body: await encryptedSavedObjects.getDecryptedAsInternalUser(
|
||||
request.params.type,
|
||||
request.params.id,
|
||||
{ namespace }
|
||||
),
|
||||
body: await encryptedSavedObjects
|
||||
.getClient()
|
||||
.getDecryptedAsInternalUser(request.params.type, request.params.id, { namespace }),
|
||||
});
|
||||
} catch (err) {
|
||||
if (encryptedSavedObjects.isEncryptionError(err)) {
|
||||
|
@ -95,6 +97,8 @@ export const plugin: PluginInitializer<void, void, PluginsSetup, PluginsStart> =
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
registerHiddenSORoutes(router, core, deps, [HIDDEN_SAVED_OBJECT_WITH_SECRET_TYPE]);
|
||||
},
|
||||
start() {},
|
||||
stop() {},
|
||||
|
|
|
@ -14,6 +14,7 @@ export default function({ getService }: FtrProviderContext) {
|
|||
const supertest = getService('supertest');
|
||||
|
||||
const SAVED_OBJECT_WITH_SECRET_TYPE = 'saved-object-with-secret';
|
||||
const HIDDEN_SAVED_OBJECT_WITH_SECRET_TYPE = 'hidden-saved-object-with-secret';
|
||||
const SAVED_OBJECT_WITH_SECRET_AND_MULTIPLE_SPACES_TYPE =
|
||||
'saved-object-with-secret-and-multiple-spaces';
|
||||
const SAVED_OBJECT_WITHOUT_SECRET_TYPE = 'saved-object-without-secret';
|
||||
|
@ -439,7 +440,7 @@ export default function({ getService }: FtrProviderContext) {
|
|||
afterEach(async () => {
|
||||
await es.deleteByQuery({
|
||||
index: '.kibana',
|
||||
q: `type:${SAVED_OBJECT_WITH_SECRET_TYPE} OR type:${SAVED_OBJECT_WITH_SECRET_AND_MULTIPLE_SPACES_TYPE} OR type:${SAVED_OBJECT_WITHOUT_SECRET_TYPE}`,
|
||||
q: `type:${SAVED_OBJECT_WITH_SECRET_TYPE} OR type:${HIDDEN_SAVED_OBJECT_WITH_SECRET_TYPE} OR type:${SAVED_OBJECT_WITH_SECRET_AND_MULTIPLE_SPACES_TYPE} OR type:${SAVED_OBJECT_WITHOUT_SECRET_TYPE}`,
|
||||
refresh: true,
|
||||
});
|
||||
});
|
||||
|
@ -453,6 +454,14 @@ export default function({ getService }: FtrProviderContext) {
|
|||
);
|
||||
});
|
||||
|
||||
describe('hidden type with `single` namespace saved object', () => {
|
||||
runTests(
|
||||
HIDDEN_SAVED_OBJECT_WITH_SECRET_TYPE,
|
||||
() => '/api/hidden_saved_objects/',
|
||||
(id, type) => generateRawId(id, type)
|
||||
);
|
||||
});
|
||||
|
||||
describe('with `multiple` namespace saved object', () => {
|
||||
runTests(
|
||||
SAVED_OBJECT_WITH_SECRET_AND_MULTIPLE_SPACES_TYPE,
|
||||
|
|
Loading…
Reference in a new issue