[Cloud Posture] Initialize plugin on package creation and on start if installed (#130649)

This commit is contained in:
Kfir Peled 2022-04-25 19:26:34 +03:00 committed by GitHub
parent dd5b807fd1
commit d5a84e1af8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 228 additions and 8 deletions

View file

@ -11,8 +11,11 @@ import { latestFindingsTransform } from './latest_findings_transform';
import { benchmarkScoreTransform } from './benchmark_score_transform';
// TODO: Move transforms to integration package
export const initializeCspTransforms = async (esClient: ElasticsearchClient, logger: Logger) => {
return Promise.all([
export const initializeCspTransforms = async (
esClient: ElasticsearchClient,
logger: Logger
): Promise<void> => {
await Promise.all([
initializeTransform(esClient, latestFindingsTransform, logger),
initializeTransform(esClient, benchmarkScoreTransform, logger),
]);

View file

@ -0,0 +1,202 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { coreMock, httpServerMock, savedObjectsClientMock } from '@kbn/core/server/mocks';
import {
createPackagePolicyServiceMock,
createArtifactsClientMock,
createMockPackageService,
createMockAgentService,
createMockAgentPolicyService,
} from '@kbn/fleet-plugin/server/mocks';
import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
import { dataPluginMock } from '@kbn/data-plugin/server/mocks';
import { CspPlugin } from './plugin';
import { CspServerPluginStartDeps } from './types';
import { createFleetAuthzMock, Installation } from '@kbn/fleet-plugin/common';
import {
ExternalCallback,
FleetStartContract,
PostPackagePolicyPostCreateCallback,
} from '@kbn/fleet-plugin/server';
import { CIS_KUBERNETES_PACKAGE_NAME } from '../common/constants';
import Chance from 'chance';
import type { AwaitedProperties } from '@kbn/utility-types';
import type { DeeplyMockedKeys } from '@kbn/utility-types/jest';
import { RequestHandlerContext } from '@kbn/core/server';
const chance = new Chance();
const mockRouteContext = {
core: {
savedObjects: {
client: savedObjectsClientMock.create(),
},
},
} as unknown as AwaitedProperties<RequestHandlerContext>;
const createMockFleetStartContract = (): DeeplyMockedKeys<FleetStartContract> => {
return {
authz: {
fromRequest: jest.fn(async (_) => createFleetAuthzMock()),
},
fleetSetupCompleted: jest.fn().mockResolvedValue(undefined),
esIndexPatternService: {
getESIndexPattern: jest.fn().mockResolvedValue(undefined),
},
// @ts-expect-error 2322
agentService: createMockAgentService(),
// @ts-expect-error 2322
packageService: createMockPackageService(),
agentPolicyService: createMockAgentPolicyService(),
registerExternalCallback: jest.fn((..._: ExternalCallback) => {}),
packagePolicyService: createPackagePolicyServiceMock(),
createArtifactsClient: jest.fn().mockReturnValue(createArtifactsClientMock()),
};
};
describe('Cloud Security Posture Plugin', () => {
describe('start()', () => {
const fleetMock = createMockFleetStartContract();
const mockPlugins: CspServerPluginStartDeps = {
fleet: fleetMock,
data: dataPluginMock.createStartContract(),
};
const contextMock = coreMock.createCustomRequestHandlerContext(mockRouteContext);
const findMock = mockRouteContext.core.savedObjects.client.find as jest.Mock;
findMock.mockReturnValue(
Promise.resolve({
saved_objects: [],
total: 0,
per_page: 0,
page: 1,
})
);
let plugin: CspPlugin;
beforeEach(() => jest.clearAllMocks());
it('should initialize when package installed', async () => {
fleetMock.packageService.asInternalUser.getInstallation.mockImplementationOnce(
async (): Promise<Installation | undefined> => {
return {} as jest.Mocked<Installation>;
}
);
const context = coreMock.createPluginInitializerContext<unknown>();
plugin = new CspPlugin(context);
const spy = jest.spyOn(plugin, 'initialize').mockImplementation();
// Act
await plugin.start(coreMock.createStart(), mockPlugins);
await mockPlugins.fleet.fleetSetupCompleted();
// Assert
expect(fleetMock.packageService.asInternalUser.getInstallation).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledTimes(1);
});
it('should not initialize when package is not installed', async () => {
fleetMock.packageService.asInternalUser.getInstallation.mockImplementationOnce(
async (): Promise<Installation | undefined> => {
return;
}
);
const context = coreMock.createPluginInitializerContext<unknown>();
plugin = new CspPlugin(context);
const spy = jest.spyOn(plugin, 'initialize').mockImplementation();
// Act
await plugin.start(coreMock.createStart(), mockPlugins);
await mockPlugins.fleet.fleetSetupCompleted();
// Assert
expect(fleetMock.packageService.asInternalUser.getInstallation).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledTimes(0);
});
it('should initialize when new package is created', async () => {
fleetMock.packageService.asInternalUser.getInstallation.mockImplementationOnce(
async (): Promise<Installation | undefined> => {
return;
}
);
const packageMock = createPackagePolicyMock();
packageMock.package!.name = CIS_KUBERNETES_PACKAGE_NAME;
const packagePolicyPostCreateCallbacks: PostPackagePolicyPostCreateCallback[] = [];
fleetMock.registerExternalCallback.mockImplementation((...args) => {
if (args[0] === 'packagePolicyPostCreate') {
packagePolicyPostCreateCallbacks.push(args[1]);
}
});
const context = coreMock.createPluginInitializerContext<unknown>();
plugin = new CspPlugin(context);
const spy = jest.spyOn(plugin, 'initialize').mockImplementation();
// Act
await plugin.start(coreMock.createStart(), mockPlugins);
await mockPlugins.fleet.fleetSetupCompleted();
// Assert
expect(fleetMock.packageService.asInternalUser.getInstallation).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledTimes(0);
expect(packagePolicyPostCreateCallbacks.length).toBeGreaterThan(0);
for (const cb of packagePolicyPostCreateCallbacks) {
await cb(packageMock, contextMock, httpServerMock.createKibanaRequest());
}
expect(spy).toHaveBeenCalledTimes(1);
});
it('should not initialize when other package is created', async () => {
fleetMock.packageService.asInternalUser.getInstallation.mockImplementationOnce(
async (): Promise<Installation | undefined> => {
return;
}
);
const packageMock = createPackagePolicyMock();
packageMock.package!.name = chance.word();
const packagePolicyPostCreateCallbacks: PostPackagePolicyPostCreateCallback[] = [];
fleetMock.registerExternalCallback.mockImplementation((...args) => {
if (args[0] === 'packagePolicyPostCreate') {
packagePolicyPostCreateCallbacks.push(args[1]);
}
});
const context = coreMock.createPluginInitializerContext<unknown>();
plugin = new CspPlugin(context);
const spy = jest.spyOn(plugin, 'initialize').mockImplementation();
// Act
await plugin.start(coreMock.createStart(), mockPlugins);
await mockPlugins.fleet.fleetSetupCompleted();
// Assert
expect(fleetMock.packageService.asInternalUser.getInstallation).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledTimes(0);
expect(packagePolicyPostCreateCallbacks.length).toBeGreaterThan(0);
for (const cb of packagePolicyPostCreateCallbacks) {
await cb(packageMock, contextMock, httpServerMock.createKibanaRequest());
}
expect(spy).toHaveBeenCalledTimes(0);
});
});
});

View file

@ -6,13 +6,14 @@
*/
import type {
KibanaRequest,
RequestHandlerContext,
PluginInitializerContext,
CoreSetup,
CoreStart,
Plugin,
Logger,
} from '@kbn/core/server';
import { KibanaRequest, RequestHandlerContext } from '@kbn/core/server';
import { DeepReadonly } from 'utility-types';
import { DeletePackagePoliciesResponse, PackagePolicy } from '@kbn/fleet-plugin/common';
import { CspAppService } from './lib/csp_app_services';
@ -81,18 +82,26 @@ export class CspPlugin
...plugins.fleet,
});
initializeCspTransformsIndices(core.elasticsearch.client.asInternalUser, this.logger).then(
(_) => initializeCspTransforms(core.elasticsearch.client.asInternalUser, this.logger)
plugins.fleet.fleetSetupCompleted().then(async () => {
const packageInfo = await plugins.fleet.packageService.asInternalUser.getInstallation(
CIS_KUBERNETES_PACKAGE_NAME
);
plugins.fleet.fleetSetupCompleted().then(() => {
// If package is installed we want to make sure all needed assets are installed
if (packageInfo) {
// noinspection ES6MissingAwait
this.initialize(core);
}
plugins.fleet.registerExternalCallback(
'packagePolicyPostCreate',
async (
packagePolicy: PackagePolicy,
context: RequestHandlerContext,
request: KibanaRequest
_: KibanaRequest
): Promise<PackagePolicy> => {
if (packagePolicy.package?.name === CIS_KUBERNETES_PACKAGE_NAME) {
await this.initialize(core);
const soClient = (await context.core).savedObjects.client;
await onPackagePolicyPostCreateCallback(this.logger, packagePolicy, soClient);
}
@ -121,4 +130,10 @@ export class CspPlugin
}
public stop() {}
async initialize(core: CoreStart): Promise<void> {
this.logger.debug('initialize');
await initializeCspTransformsIndices(core.elasticsearch.client.asInternalUser, this.logger);
await initializeCspTransforms(core.elasticsearch.client.asInternalUser, this.logger);
}
}