mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[8.x] [Security Solution][Endpoint] changes to Endpoint metadata API in support of space awareness (#193490) (#194309)
# Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution][Endpoint] changes to Endpoint metadata API in support of space awareness (#193490)](https://github.com/elastic/kibana/pull/193490) <!--- Backport version: 8.9.8 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Paul Tavares","email":"56442535+paul-tavares@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-09-27T14:38:17Z","message":"[Security Solution][Endpoint] changes to Endpoint metadata API in support of space awareness (#193490)\n\n## Summary\r\n\r\n### Fleet Plugin\r\n\r\n- Added some mocks and updates others\r\n\r\n\r\n### Security Solution\r\n\r\nThe following refactoring changes were done in preparation for\r\nforthcoming work for supporting kibana spaces:\r\n\r\n- A new saved objects client factory service was introduced for use in\r\n`EndpointAppContextServices`\r\n- Deleted older saved objects client utilities\r\n- Simplified the list of options passed to\r\n`EndpointAppContextService#start()` method\r\n- Updated `EndpiontFleetServicesFactory` with:\r\n - simpler list of constructor arguments\r\n - changed members of object return by `asInternalUser()`\r\n- Refactored the `EndpintMetadataService` to:\r\n - take in simplified constructor arguments\r\n- Simplified most methods of the class with removal all ES Client, SO\r\nClient or Fleet services arguments from class method calling signatures.\r\nThese are not provided to the service class upon initialization and can\r\nbe accessed internally by the methods\r\n- Updates to Mocks and tests to reflect the above changes","sha":"0b1e9f475440d60260203ce2a85c8b57c4363130","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Fleet","v9.0.0","Team:Defend Workflows","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-infra_services","apm:review","v8.16.0"],"number":193490,"url":"https://github.com/elastic/kibana/pull/193490","mergeCommit":{"message":"[Security Solution][Endpoint] changes to Endpoint metadata API in support of space awareness (#193490)\n\n## Summary\r\n\r\n### Fleet Plugin\r\n\r\n- Added some mocks and updates others\r\n\r\n\r\n### Security Solution\r\n\r\nThe following refactoring changes were done in preparation for\r\nforthcoming work for supporting kibana spaces:\r\n\r\n- A new saved objects client factory service was introduced for use in\r\n`EndpointAppContextServices`\r\n- Deleted older saved objects client utilities\r\n- Simplified the list of options passed to\r\n`EndpointAppContextService#start()` method\r\n- Updated `EndpiontFleetServicesFactory` with:\r\n - simpler list of constructor arguments\r\n - changed members of object return by `asInternalUser()`\r\n- Refactored the `EndpintMetadataService` to:\r\n - take in simplified constructor arguments\r\n- Simplified most methods of the class with removal all ES Client, SO\r\nClient or Fleet services arguments from class method calling signatures.\r\nThese are not provided to the service class upon initialization and can\r\nbe accessed internally by the methods\r\n- Updates to Mocks and tests to reflect the above changes","sha":"0b1e9f475440d60260203ce2a85c8b57c4363130"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193490","number":193490,"mergeCommit":{"message":"[Security Solution][Endpoint] changes to Endpoint metadata API in support of space awareness (#193490)\n\n## Summary\r\n\r\n### Fleet Plugin\r\n\r\n- Added some mocks and updates others\r\n\r\n\r\n### Security Solution\r\n\r\nThe following refactoring changes were done in preparation for\r\nforthcoming work for supporting kibana spaces:\r\n\r\n- A new saved objects client factory service was introduced for use in\r\n`EndpointAppContextServices`\r\n- Deleted older saved objects client utilities\r\n- Simplified the list of options passed to\r\n`EndpointAppContextService#start()` method\r\n- Updated `EndpiontFleetServicesFactory` with:\r\n - simpler list of constructor arguments\r\n - changed members of object return by `asInternalUser()`\r\n- Refactored the `EndpintMetadataService` to:\r\n - take in simplified constructor arguments\r\n- Simplified most methods of the class with removal all ES Client, SO\r\nClient or Fleet services arguments from class method calling signatures.\r\nThese are not provided to the service class upon initialization and can\r\nbe accessed internally by the methods\r\n- Updates to Mocks and tests to reflect the above changes","sha":"0b1e9f475440d60260203ce2a85c8b57c4363130"}},{"branch":"8.x","label":"v8.16.0","labelRegex":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
This commit is contained in:
parent
a4d9e01317
commit
1448ec5076
44 changed files with 749 additions and 808 deletions
|
@ -11,29 +11,16 @@ import {
|
|||
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 { CloudDefendPlugin } from './plugin';
|
||||
import { CloudDefendPluginStartDeps } from './types';
|
||||
import { createFleetAuthzMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import { PackagePolicy, UpdatePackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
ExternalCallback,
|
||||
FleetStartContract,
|
||||
PostPackagePolicyPostCreateCallback,
|
||||
} from '@kbn/fleet-plugin/server';
|
||||
import { PostPackagePolicyPostCreateCallback } from '@kbn/fleet-plugin/server';
|
||||
import { INTEGRATION_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 {
|
||||
ElasticsearchClient,
|
||||
RequestHandlerContext,
|
||||
|
@ -42,6 +29,7 @@ import {
|
|||
import { securityMock } from '@kbn/security-plugin/server/mocks';
|
||||
import { licensingMock } from '@kbn/licensing-plugin/server/mocks';
|
||||
import * as onPackagePolicyPostCreateCallback from './lib/fleet_util';
|
||||
import { createFleetStartContractMock } from '@kbn/fleet-plugin/server/mocks';
|
||||
|
||||
const chance = new Chance();
|
||||
|
||||
|
@ -49,26 +37,9 @@ const mockRouteContext = {
|
|||
core: coreMock.createRequestHandlerContext(),
|
||||
} as unknown as AwaitedProperties<RequestHandlerContext>;
|
||||
|
||||
const createMockFleetStartContract = (): DeeplyMockedKeys<FleetStartContract> => {
|
||||
return {
|
||||
authz: {
|
||||
fromRequest: jest.fn(async (_) => createFleetAuthzMock()),
|
||||
},
|
||||
fleetSetupCompleted: 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 Defend Plugin', () => {
|
||||
describe('start()', () => {
|
||||
const fleetMock = createMockFleetStartContract();
|
||||
const fleetMock = createFleetStartContractMock();
|
||||
const mockPlugins: CloudDefendPluginStartDeps = {
|
||||
fleet: fleetMock,
|
||||
data: dataPluginMock.createStartContract(),
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
"@kbn/es-types",
|
||||
"@kbn/data-views-plugin",
|
||||
"@kbn/utility-types",
|
||||
"@kbn/utility-types-jest",
|
||||
"@kbn/kubernetes-security-plugin",
|
||||
"@kbn/core-http-router-server-mocks",
|
||||
"@kbn/core-elasticsearch-server",
|
||||
|
|
|
@ -11,20 +11,13 @@ import {
|
|||
httpServerMock,
|
||||
savedObjectsClientMock,
|
||||
} from '@kbn/core/server/mocks';
|
||||
import {
|
||||
createPackagePolicyServiceMock,
|
||||
createArtifactsClientMock,
|
||||
createMockPackageService,
|
||||
createMockAgentService,
|
||||
createMockAgentPolicyService,
|
||||
} from '@kbn/fleet-plugin/server/mocks';
|
||||
import { createFleetStartContractMock } from '@kbn/fleet-plugin/server/mocks';
|
||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||
|
||||
import { createPackagePolicyMock, deletePackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/server/mocks';
|
||||
import { CspPlugin } from './plugin';
|
||||
import { CspServerPluginStartDeps } from './types';
|
||||
import { createFleetAuthzMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import {
|
||||
Installation,
|
||||
ListResult,
|
||||
|
@ -32,15 +25,12 @@ import {
|
|||
UpdatePackagePolicy,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
FleetStartContract,
|
||||
PostPackagePolicyPostDeleteCallback,
|
||||
PostPackagePolicyPostCreateCallback,
|
||||
ExternalCallback,
|
||||
} from '@kbn/fleet-plugin/server';
|
||||
import { CLOUD_SECURITY_POSTURE_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 { createIndexPatternsStartMock } from '@kbn/data-views-plugin/server/mocks';
|
||||
import {
|
||||
ElasticsearchClient,
|
||||
|
@ -56,26 +46,9 @@ const mockRouteContext = {
|
|||
core: coreMock.createRequestHandlerContext(),
|
||||
} as unknown as AwaitedProperties<RequestHandlerContext>;
|
||||
|
||||
const createMockFleetStartContract = (): DeeplyMockedKeys<FleetStartContract> => {
|
||||
return {
|
||||
authz: {
|
||||
fromRequest: jest.fn(async (_) => createFleetAuthzMock()),
|
||||
},
|
||||
fleetSetupCompleted: 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 fleetMock = createFleetStartContractMock();
|
||||
const mockPlugins: CspServerPluginStartDeps = {
|
||||
fleet: fleetMock,
|
||||
data: dataPluginMock.createStartContract(),
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
"@kbn/monaco",
|
||||
"@kbn/utility-types",
|
||||
"@kbn/core-logging-server-mocks",
|
||||
"@kbn/utility-types-jest",
|
||||
"@kbn/securitysolution-es-utils",
|
||||
"@kbn/core-elasticsearch-client-server-mocks",
|
||||
"@kbn/core-elasticsearch-server",
|
||||
|
|
|
@ -22,9 +22,17 @@ import { cloudMock } from '@kbn/cloud-plugin/public/mocks';
|
|||
import { SPACES_EXTENSION_ID } from '@kbn/core-saved-objects-server';
|
||||
import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server';
|
||||
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
|
||||
import { createFleetActionsClientMock } from '../services/actions/mocks';
|
||||
|
||||
import { createFleetFilesClientFactoryMock } from '../services/files/mocks';
|
||||
|
||||
import { createArtifactsClientMock } from '../services/artifacts/mocks';
|
||||
|
||||
import type { PackagePolicyClient } from '../services/package_policy_service';
|
||||
import type { AgentPolicyServiceInterface } from '../services';
|
||||
import type { FleetAppContext } from '../plugin';
|
||||
import type { FleetAppContext, FleetStartContract } from '../plugin';
|
||||
import { createMockTelemetryEventsSender } from '../telemetry/__mocks__';
|
||||
import type { FleetConfigType } from '../../common/types';
|
||||
import type { ExperimentalFeatures } from '../../common/experimental_features';
|
||||
|
@ -35,6 +43,8 @@ import { packageServiceMock } from '../services/epm/package_service.mock';
|
|||
import type { UninstallTokenServiceInterface } from '../services/security/uninstall_token_service';
|
||||
import type { MessageSigningServiceInterface } from '../services/security';
|
||||
|
||||
import { getPackageSpecTagId } from '../services/epm/kibana/assets/tag_assets';
|
||||
|
||||
import { PackagePolicyMocks } from './package_policy.mocks';
|
||||
|
||||
// Export all mocks from artifacts
|
||||
|
@ -238,7 +248,7 @@ export const createMockAgentClient = () => agentServiceMock.createClient();
|
|||
*/
|
||||
export const createMockPackageService = () => packageServiceMock.create();
|
||||
|
||||
export function createMessageSigningServiceMock(): MessageSigningServiceInterface {
|
||||
export function createMessageSigningServiceMock(): jest.Mocked<MessageSigningServiceInterface> {
|
||||
return {
|
||||
isEncryptionAvailable: true,
|
||||
generateKeyPair: jest.fn(),
|
||||
|
@ -253,7 +263,7 @@ export function createMessageSigningServiceMock(): MessageSigningServiceInterfac
|
|||
};
|
||||
}
|
||||
|
||||
export function createUninstallTokenServiceMock(): UninstallTokenServiceInterface {
|
||||
export function createUninstallTokenServiceMock(): DeeplyMockedKeys<UninstallTokenServiceInterface> {
|
||||
return {
|
||||
getToken: jest.fn(),
|
||||
getTokenMetadata: jest.fn(),
|
||||
|
@ -269,3 +279,27 @@ export function createUninstallTokenServiceMock(): UninstallTokenServiceInterfac
|
|||
scoped: jest.fn().mockImplementation(() => createUninstallTokenServiceMock()),
|
||||
};
|
||||
}
|
||||
|
||||
export const createFleetStartContractMock = (): DeeplyMockedKeys<FleetStartContract> => {
|
||||
const fleetAuthzMock = createFleetAuthzMock();
|
||||
const fleetArtifactsClient = createArtifactsClientMock();
|
||||
const fleetActionsClient = createFleetActionsClientMock();
|
||||
|
||||
const startContract: DeeplyMockedKeys<FleetStartContract> = {
|
||||
fleetSetupCompleted: jest.fn(async () => {}),
|
||||
authz: { fromRequest: jest.fn(async (_) => fleetAuthzMock) },
|
||||
packageService: createMockPackageService(),
|
||||
agentService: createMockAgentService(),
|
||||
packagePolicyService: createPackagePolicyServiceMock(),
|
||||
agentPolicyService: createMockAgentPolicyService(),
|
||||
registerExternalCallback: jest.fn(),
|
||||
createArtifactsClient: jest.fn((_) => fleetArtifactsClient),
|
||||
createFilesClient: createFleetFilesClientFactoryMock(),
|
||||
messageSigningService: createMessageSigningServiceMock(),
|
||||
uninstallTokenService: createUninstallTokenServiceMock(),
|
||||
createFleetActionsClient: jest.fn((_) => fleetActionsClient),
|
||||
getPackageSpecTagId: jest.fn(getPackageSpecTagId),
|
||||
};
|
||||
|
||||
return startContract;
|
||||
};
|
||||
|
|
|
@ -72,6 +72,7 @@ import {
|
|||
AGENT_POLICY_SAVED_OBJECT_TYPE,
|
||||
LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE,
|
||||
} from '../common/constants';
|
||||
|
||||
import { getFilesClientFactory } from './services/files/get_files_client_factory';
|
||||
|
||||
import type { MessageSigningServiceInterface } from './services/security';
|
||||
|
@ -98,7 +99,12 @@ import { registerEncryptedSavedObjects, registerSavedObjects } from './saved_obj
|
|||
import { registerRoutes } from './routes';
|
||||
|
||||
import type { ExternalCallback, FleetRequestHandlerContext } from './types';
|
||||
import type { AgentPolicyServiceInterface, AgentService, PackageService } from './services';
|
||||
import type {
|
||||
AgentPolicyServiceInterface,
|
||||
AgentService,
|
||||
ArtifactsClientInterface,
|
||||
PackageService,
|
||||
} from './services';
|
||||
import {
|
||||
agentPolicyService,
|
||||
AgentServiceImpl,
|
||||
|
@ -236,7 +242,7 @@ export interface FleetStartContract {
|
|||
* Create a Fleet Artifact Client instance
|
||||
* @param packageName
|
||||
*/
|
||||
createArtifactsClient: (packageName: string) => FleetArtifactsClient;
|
||||
createArtifactsClient: (packageName: string) => ArtifactsClientInterface;
|
||||
|
||||
/**
|
||||
* Create a Fleet Files client instance
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
|
||||
import type { AgentClient, AgentService } from './agent_service';
|
||||
|
||||
const createClientMock = (): jest.Mocked<AgentClient> => ({
|
||||
|
@ -15,7 +17,7 @@ const createClientMock = (): jest.Mocked<AgentClient> => ({
|
|||
getLatestAgentAvailableVersion: jest.fn(),
|
||||
});
|
||||
|
||||
const createServiceMock = (): jest.Mocked<AgentService> => ({
|
||||
const createServiceMock = (): DeeplyMockedKeys<AgentService> => ({
|
||||
asInternalUser: createClientMock(),
|
||||
asScoped: jest.fn().mockReturnValue(createClientMock()),
|
||||
});
|
||||
|
|
|
@ -12,6 +12,8 @@ import { errors } from '@elastic/elasticsearch';
|
|||
import { elasticsearchServiceMock } from '@kbn/core/server/mocks';
|
||||
import type { SearchHit, ESSearchResponse } from '@kbn/es-types';
|
||||
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
|
||||
import type {
|
||||
Artifact,
|
||||
ArtifactElasticsearchProperties,
|
||||
|
@ -20,7 +22,7 @@ import type {
|
|||
} from './types';
|
||||
import { newArtifactToElasticsearchProperties } from './mappings';
|
||||
|
||||
export const createArtifactsClientMock = (): jest.Mocked<ArtifactsClientInterface> => {
|
||||
export const createArtifactsClientMock = (): DeeplyMockedKeys<ArtifactsClientInterface> => {
|
||||
return {
|
||||
getArtifact: jest.fn().mockResolvedValue(generateArtifactMock()),
|
||||
createArtifact: jest.fn().mockResolvedValue(generateArtifactMock()),
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
|
||||
import type { PackageClient, PackageService } from './package_service';
|
||||
|
||||
const createClientMock = (): jest.Mocked<PackageClient> => ({
|
||||
|
@ -21,8 +23,8 @@ const createClientMock = (): jest.Mocked<PackageClient> => ({
|
|||
reinstallEsAssets: jest.fn(),
|
||||
});
|
||||
|
||||
const createServiceMock = (): PackageService => ({
|
||||
asScoped: jest.fn(createClientMock),
|
||||
const createServiceMock = (): DeeplyMockedKeys<PackageService> => ({
|
||||
asScoped: jest.fn((_) => createClientMock()),
|
||||
asInternalUser: createClientMock(),
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,10 @@ import { Readable } from 'stream';
|
|||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
|
||||
import type {
|
||||
FilesClientFactory,
|
||||
FleetFile,
|
||||
FleetFromHostFileClientInterface,
|
||||
FleetToHostFileClientInterface,
|
||||
|
@ -153,3 +156,10 @@ export const createHapiReadableStreamMock = (): HapiReadableStream => {
|
|||
|
||||
return readable;
|
||||
};
|
||||
|
||||
export const createFleetFilesClientFactoryMock = (): DeeplyMockedKeys<FilesClientFactory> => {
|
||||
return {
|
||||
toHost: jest.fn((_) => createFleetToHostFilesClientMock()),
|
||||
fromHost: jest.fn((_) => createFleetFromHostFilesClientMock()),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
|
||||
import { FleetStartContract } from '@kbn/fleet-plugin/server';
|
||||
import { FleetArtifactsClient } from '@kbn/fleet-plugin/server/services';
|
||||
import { ArtifactsClientInterface } from '@kbn/fleet-plugin/server/services';
|
||||
import { TaskManagerSetupContract } from '@kbn/task-manager-plugin/server';
|
||||
import { CoreStart, Logger } from '@kbn/core/server';
|
||||
import { getApmArtifactClient } from '../fleet/source_maps';
|
||||
|
@ -141,7 +141,7 @@ async function getArtifactsForPage({
|
|||
kuery,
|
||||
}: {
|
||||
page: number;
|
||||
apmArtifactClient: FleetArtifactsClient;
|
||||
apmArtifactClient: ArtifactsClientInterface;
|
||||
kuery: string;
|
||||
}) {
|
||||
return await apmArtifactClient.listArtifacts({
|
||||
|
@ -163,7 +163,7 @@ async function paginateArtifacts({
|
|||
}: {
|
||||
taskState?: TaskState;
|
||||
page: number;
|
||||
apmArtifactClient: FleetArtifactsClient;
|
||||
apmArtifactClient: ArtifactsClientInterface;
|
||||
kuery: string;
|
||||
logger: Logger;
|
||||
internalESClient: ElasticsearchClient;
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
import type {
|
||||
AnalyticsServiceSetup,
|
||||
ElasticsearchClient,
|
||||
HttpServiceSetup,
|
||||
KibanaRequest,
|
||||
Logger,
|
||||
LoggerFactory,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsServiceStart,
|
||||
SecurityServiceStart,
|
||||
} from '@kbn/core/server';
|
||||
import type { ExceptionListClient, ListsServerExtensionRegistrar } from '@kbn/lists-plugin/server';
|
||||
|
@ -25,6 +25,8 @@ import type { PluginStartContract as AlertsPluginStartContract } from '@kbn/aler
|
|||
import type { CloudSetup } from '@kbn/cloud-plugin/server';
|
||||
import type { FleetActionsClientInterface } from '@kbn/fleet-plugin/server/services/actions/types';
|
||||
import type { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server';
|
||||
import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common';
|
||||
import { SavedObjectsClientFactory } from './services/saved_objects';
|
||||
import type { ResponseActionsClient } from './services';
|
||||
import { getResponseActionsClient, NormalizedExternalConnectorClient } from './services';
|
||||
import {
|
||||
|
@ -39,7 +41,7 @@ import type { ManifestManager } from './services/artifacts';
|
|||
import type { ConfigType } from '../config';
|
||||
import type { IRequestContextFactory } from '../request_context_factory';
|
||||
import type { LicenseService } from '../../common/license';
|
||||
import type { EndpointMetadataService } from './services/metadata';
|
||||
import { EndpointMetadataService } from './services/metadata';
|
||||
import {
|
||||
EndpointAppContentServicesNotSetUpError,
|
||||
EndpointAppContentServicesNotStartedError,
|
||||
|
@ -48,6 +50,7 @@ import type {
|
|||
EndpointFleetServicesFactoryInterface,
|
||||
EndpointInternalFleetServicesInterface,
|
||||
} from './services/fleet/endpoint_fleet_services_factory';
|
||||
import { EndpointFleetServicesFactory } from './services/fleet/endpoint_fleet_services_factory';
|
||||
import { registerListsPluginEndpointExtensionPoints } from '../lists_integration';
|
||||
import type { EndpointAuthz } from '../../common/endpoint/types/authz';
|
||||
import { calculateEndpointAuthz } from '../../common/endpoint/service/authz';
|
||||
|
@ -55,35 +58,31 @@ import type { FeatureUsageService } from './services/feature_usage/service';
|
|||
import type { ExperimentalFeatures } from '../../common/experimental_features';
|
||||
import type { ProductFeaturesService } from '../lib/product_features_service/product_features_service';
|
||||
import type { ResponseActionAgentType } from '../../common/endpoint/service/response_actions/constants';
|
||||
|
||||
export interface EndpointAppContextServiceSetupContract {
|
||||
securitySolutionRequestContextFactory: IRequestContextFactory;
|
||||
cloud: CloudSetup;
|
||||
loggerFactory: LoggerFactory;
|
||||
telemetry: AnalyticsServiceSetup;
|
||||
httpServiceSetup: HttpServiceSetup;
|
||||
}
|
||||
|
||||
export interface EndpointAppContextServiceStartContract {
|
||||
fleetAuthzService?: FleetStartContract['authz'];
|
||||
createFleetFilesClient: FleetStartContract['createFilesClient'];
|
||||
createFleetActionsClient: FleetStartContract['createFleetActionsClient'];
|
||||
logger: Logger;
|
||||
endpointMetadataService: EndpointMetadataService;
|
||||
endpointFleetServicesFactory: EndpointFleetServicesFactoryInterface;
|
||||
manifestManager?: ManifestManager;
|
||||
fleetStartServices: FleetStartContract;
|
||||
manifestManager: ManifestManager;
|
||||
security: SecurityServiceStart;
|
||||
alerting: AlertsPluginStartContract;
|
||||
config: ConfigType;
|
||||
registerIngestCallback?: FleetStartContract['registerExternalCallback'];
|
||||
registerListsServerExtension?: ListsServerExtensionRegistrar;
|
||||
licenseService: LicenseService;
|
||||
exceptionListsClient: ExceptionListClient | undefined;
|
||||
cases: CasesServerStart | undefined;
|
||||
featureUsageService: FeatureUsageService;
|
||||
experimentalFeatures: ExperimentalFeatures;
|
||||
messageSigningService: MessageSigningServiceInterface | undefined;
|
||||
/** An internal ES client */
|
||||
esClient: ElasticsearchClient;
|
||||
productFeaturesService: ProductFeaturesService;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
savedObjectsServiceStart: SavedObjectsServiceStart;
|
||||
connectorActions: ActionsPluginStartContract;
|
||||
}
|
||||
|
||||
|
@ -95,6 +94,8 @@ export class EndpointAppContextService {
|
|||
private setupDependencies: EndpointAppContextServiceSetupContract | null = null;
|
||||
private startDependencies: EndpointAppContextServiceStartContract | null = null;
|
||||
private fleetServicesFactory: EndpointFleetServicesFactoryInterface | null = null;
|
||||
private savedObjectsFactoryService: SavedObjectsClientFactory | null = null;
|
||||
|
||||
public security: SecurityServiceStart | undefined;
|
||||
|
||||
public setup(dependencies: EndpointAppContextServiceSetupContract) {
|
||||
|
@ -106,92 +107,128 @@ export class EndpointAppContextService {
|
|||
throw new EndpointAppContentServicesNotSetUpError();
|
||||
}
|
||||
|
||||
const savedObjectsFactory = new SavedObjectsClientFactory(
|
||||
dependencies.savedObjectsServiceStart,
|
||||
this.setupDependencies.httpServiceSetup
|
||||
);
|
||||
|
||||
this.startDependencies = dependencies;
|
||||
this.security = dependencies.security;
|
||||
this.fleetServicesFactory = dependencies.endpointFleetServicesFactory;
|
||||
this.savedObjectsFactoryService = savedObjectsFactory;
|
||||
this.fleetServicesFactory = new EndpointFleetServicesFactory(
|
||||
dependencies.fleetStartServices,
|
||||
savedObjectsFactory
|
||||
);
|
||||
|
||||
if (dependencies.registerIngestCallback && dependencies.manifestManager) {
|
||||
const {
|
||||
registerIngestCallback,
|
||||
logger,
|
||||
manifestManager,
|
||||
alerting,
|
||||
licenseService,
|
||||
exceptionListsClient,
|
||||
featureUsageService,
|
||||
endpointMetadataService,
|
||||
esClient,
|
||||
productFeaturesService,
|
||||
savedObjectsClient,
|
||||
} = dependencies;
|
||||
this.registerFleetExtensions();
|
||||
this.registerListsExtensions();
|
||||
}
|
||||
|
||||
registerIngestCallback(
|
||||
'agentPolicyCreate',
|
||||
getAgentPolicyCreateCallback(logger, productFeaturesService)
|
||||
public stop() {
|
||||
this.startDependencies = null;
|
||||
this.savedObjectsFactoryService = null;
|
||||
}
|
||||
|
||||
private registerListsExtensions() {
|
||||
if (this.startDependencies?.registerListsServerExtension) {
|
||||
registerListsPluginEndpointExtensionPoints(
|
||||
this.startDependencies?.registerListsServerExtension,
|
||||
this
|
||||
);
|
||||
registerIngestCallback(
|
||||
'agentPolicyUpdate',
|
||||
getAgentPolicyUpdateCallback(logger, productFeaturesService)
|
||||
);
|
||||
|
||||
registerIngestCallback(
|
||||
'packagePolicyCreate',
|
||||
getPackagePolicyCreateCallback(
|
||||
logger,
|
||||
manifestManager,
|
||||
this.setupDependencies.securitySolutionRequestContextFactory,
|
||||
alerting,
|
||||
licenseService,
|
||||
exceptionListsClient,
|
||||
this.setupDependencies.cloud,
|
||||
productFeaturesService
|
||||
)
|
||||
);
|
||||
|
||||
registerIngestCallback(
|
||||
'packagePolicyPostCreate',
|
||||
getPackagePolicyPostCreateCallback(logger, exceptionListsClient)
|
||||
);
|
||||
|
||||
registerIngestCallback(
|
||||
'packagePolicyUpdate',
|
||||
getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
featureUsageService,
|
||||
endpointMetadataService,
|
||||
this.setupDependencies.cloud,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
)
|
||||
);
|
||||
|
||||
registerIngestCallback(
|
||||
'packagePolicyPostDelete',
|
||||
getPackagePolicyDeleteCallback(exceptionListsClient, savedObjectsClient)
|
||||
);
|
||||
}
|
||||
|
||||
if (this.startDependencies.registerListsServerExtension) {
|
||||
const { registerListsServerExtension } = this.startDependencies;
|
||||
|
||||
registerListsPluginEndpointExtensionPoints(registerListsServerExtension, this);
|
||||
}
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
||||
private getFleetAuthzService(): FleetStartContract['authz'] {
|
||||
if (!this.startDependencies?.fleetAuthzService) {
|
||||
private registerFleetExtensions() {
|
||||
if (!this.setupDependencies) {
|
||||
throw new EndpointAppContentServicesNotSetUpError();
|
||||
}
|
||||
if (!this.startDependencies) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
|
||||
return this.startDependencies.fleetAuthzService;
|
||||
const {
|
||||
fleetStartServices: { registerExternalCallback: registerFleetCallback },
|
||||
manifestManager,
|
||||
alerting,
|
||||
licenseService,
|
||||
exceptionListsClient,
|
||||
featureUsageService,
|
||||
esClient,
|
||||
productFeaturesService,
|
||||
} = this.startDependencies;
|
||||
const endpointMetadataService = this.getEndpointMetadataService();
|
||||
const soClient = this.savedObjects.createInternalScopedSoClient({ readonly: false });
|
||||
const logger = this.createLogger('endpointFleetExtension');
|
||||
|
||||
registerFleetCallback(
|
||||
'agentPolicyCreate',
|
||||
getAgentPolicyCreateCallback(logger, productFeaturesService)
|
||||
);
|
||||
registerFleetCallback(
|
||||
'agentPolicyUpdate',
|
||||
getAgentPolicyUpdateCallback(logger, productFeaturesService)
|
||||
);
|
||||
|
||||
registerFleetCallback(
|
||||
'packagePolicyCreate',
|
||||
getPackagePolicyCreateCallback(
|
||||
logger,
|
||||
manifestManager,
|
||||
this.setupDependencies.securitySolutionRequestContextFactory,
|
||||
alerting,
|
||||
licenseService,
|
||||
exceptionListsClient,
|
||||
this.setupDependencies.cloud,
|
||||
productFeaturesService
|
||||
)
|
||||
);
|
||||
|
||||
registerFleetCallback(
|
||||
'packagePolicyPostCreate',
|
||||
getPackagePolicyPostCreateCallback(logger, exceptionListsClient)
|
||||
);
|
||||
|
||||
registerFleetCallback(
|
||||
'packagePolicyUpdate',
|
||||
getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
featureUsageService,
|
||||
endpointMetadataService,
|
||||
this.setupDependencies.cloud,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
)
|
||||
);
|
||||
|
||||
registerFleetCallback(
|
||||
'packagePolicyPostDelete',
|
||||
getPackagePolicyDeleteCallback(exceptionListsClient, soClient)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Property providing access to saved objects client factory
|
||||
*/
|
||||
public get savedObjects(): SavedObjectsClientFactory {
|
||||
if (!this.savedObjectsFactoryService) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
|
||||
return this.savedObjectsFactoryService;
|
||||
}
|
||||
|
||||
private getFleetAuthzService(): FleetStartContract['authz'] {
|
||||
if (!this.startDependencies?.fleetStartServices) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
|
||||
return this.startDependencies.fleetStartServices.authz;
|
||||
}
|
||||
|
||||
public createLogger(...contextParts: string[]) {
|
||||
if (!this.setupDependencies?.loggerFactory) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
throw new EndpointAppContentServicesNotSetUpError();
|
||||
}
|
||||
|
||||
return this.setupDependencies.loggerFactory.get(...contextParts);
|
||||
|
@ -211,11 +248,17 @@ export class EndpointAppContextService {
|
|||
);
|
||||
}
|
||||
|
||||
public getEndpointMetadataService(): EndpointMetadataService {
|
||||
public getEndpointMetadataService(spaceId: string = DEFAULT_SPACE_ID): EndpointMetadataService {
|
||||
if (this.startDependencies == null) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
return this.startDependencies.endpointMetadataService;
|
||||
|
||||
return new EndpointMetadataService(
|
||||
this.startDependencies.esClient,
|
||||
this.savedObjects.createInternalScopedSoClient({ readonly: false }),
|
||||
this.getInternalFleetServices(),
|
||||
this.createLogger('endpointMetadata')
|
||||
);
|
||||
}
|
||||
|
||||
public getInternalFleetServices(): EndpointInternalFleetServicesInterface {
|
||||
|
@ -268,11 +311,11 @@ export class EndpointAppContextService {
|
|||
}
|
||||
|
||||
public getMessageSigningService(): MessageSigningServiceInterface {
|
||||
if (!this.startDependencies?.messageSigningService) {
|
||||
if (!this.startDependencies?.fleetStartServices.messageSigningService) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
|
||||
return this.startDependencies.messageSigningService;
|
||||
return this.startDependencies?.fleetStartServices.messageSigningService;
|
||||
}
|
||||
|
||||
public getInternalResponseActionsClient({
|
||||
|
@ -316,30 +359,30 @@ export class EndpointAppContextService {
|
|||
}
|
||||
|
||||
public async getFleetToHostFilesClient() {
|
||||
if (!this.startDependencies?.createFleetFilesClient) {
|
||||
if (!this.startDependencies?.fleetStartServices) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
|
||||
return this.startDependencies.createFleetFilesClient.toHost(
|
||||
return this.startDependencies.fleetStartServices.createFilesClient.toHost(
|
||||
'endpoint',
|
||||
this.startDependencies.config.maxUploadResponseActionFileBytes
|
||||
);
|
||||
}
|
||||
|
||||
public async getFleetFromHostFilesClient(): Promise<FleetFromHostFileClientInterface> {
|
||||
if (!this.startDependencies?.createFleetFilesClient) {
|
||||
if (!this.startDependencies?.fleetStartServices) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
|
||||
return this.startDependencies.createFleetFilesClient.fromHost('endpoint');
|
||||
return this.startDependencies.fleetStartServices.createFilesClient.fromHost('endpoint');
|
||||
}
|
||||
|
||||
public async getFleetActionsClient(): Promise<FleetActionsClientInterface> {
|
||||
if (!this.startDependencies?.createFleetActionsClient) {
|
||||
if (!this.startDependencies?.fleetStartServices) {
|
||||
throw new EndpointAppContentServicesNotStartedError();
|
||||
}
|
||||
|
||||
return this.startDependencies.createFleetActionsClient('endpoint');
|
||||
return this.startDependencies.fleetStartServices.createFleetActionsClient('endpoint');
|
||||
}
|
||||
|
||||
public getTelemetryService(): AnalyticsServiceSetup {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createMockEndpointAppContextServiceStartContract } from '../mocks';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import type { EndpointInternalFleetServicesInterface } from '../services/fleet';
|
||||
|
||||
|
@ -13,6 +12,9 @@ import { ALL_PRODUCT_FEATURE_KEYS } from '@kbn/security-solution-features/keys';
|
|||
import type { ProductFeaturesService } from '../../lib/product_features_service/product_features_service';
|
||||
import { createProductFeaturesServiceMock } from '../../lib/product_features_service/mocks';
|
||||
import { turnOffAgentPolicyFeatures } from './turn_off_agent_policy_features';
|
||||
import { createEndpointFleetServicesFactoryMock } from '../services/fleet/endpoint_fleet_services_factory.mocks';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { allowedExperimentalValues } from '../../../common';
|
||||
|
||||
describe('Turn Off Agent Policy Features Migration', () => {
|
||||
let fleetServices: EndpointInternalFleetServicesInterface;
|
||||
|
@ -23,12 +25,16 @@ describe('Turn Off Agent Policy Features Migration', () => {
|
|||
turnOffAgentPolicyFeatures(fleetServices, productFeatureService, logger);
|
||||
|
||||
beforeEach(() => {
|
||||
const endpointContextStartContract = createMockEndpointAppContextServiceStartContract();
|
||||
const mockedFleetServices = createEndpointFleetServicesFactoryMock();
|
||||
|
||||
({ logger } = endpointContextStartContract);
|
||||
|
||||
productFeatureService = endpointContextStartContract.productFeaturesService;
|
||||
fleetServices = endpointContextStartContract.endpointFleetServicesFactory.asInternalUser();
|
||||
fleetServices = mockedFleetServices.service.asInternalUser();
|
||||
logger = loggingSystemMock.createLogger();
|
||||
productFeatureService = createProductFeaturesServiceMock(
|
||||
undefined,
|
||||
allowedExperimentalValues,
|
||||
undefined,
|
||||
logger
|
||||
);
|
||||
});
|
||||
|
||||
describe('and `agentTamperProtection` is enabled', () => {
|
||||
|
|
|
@ -29,7 +29,8 @@ export const turnOffAgentPolicyFeatures = async (
|
|||
`App feature [${ProductFeatureSecurityKey.endpointAgentTamperProtection}] is disabled. Checking fleet agent policies for compliance`
|
||||
);
|
||||
|
||||
const { agentPolicy: agentPolicyService, internalSoClient } = fleetServices;
|
||||
const { agentPolicy: agentPolicyService, savedObjects } = fleetServices;
|
||||
const internalSoClient = savedObjects.createInternalScopedSoClient({ readonly: false });
|
||||
const { updatedPolicies, failedPolicies } =
|
||||
await agentPolicyService.turnOffAgentTamperProtections(internalSoClient);
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ import type { PromiseResolvedValue } from '../../../common/endpoint/types/utilit
|
|||
import { ensureOnlyEventCollectionIsAllowed } from '../../../common/endpoint/models/policy_config_helpers';
|
||||
import type { ProductFeaturesService } from '../../lib/product_features_service/product_features_service';
|
||||
import { createProductFeaturesServiceMock } from '../../lib/product_features_service/mocks';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { createEndpointFleetServicesFactoryMock } from '../services/fleet/endpoint_fleet_services_factory.mocks';
|
||||
|
||||
describe('Turn Off Policy Protections Migration', () => {
|
||||
let esClient: ElasticsearchClient;
|
||||
|
@ -58,10 +60,11 @@ describe('Turn Off Policy Protections Migration', () => {
|
|||
beforeEach(() => {
|
||||
const endpointContextStartContract = createMockEndpointAppContextServiceStartContract();
|
||||
|
||||
({ esClient, logger } = endpointContextStartContract);
|
||||
|
||||
logger = loggingSystemMock.createLogger();
|
||||
({ esClient } = endpointContextStartContract);
|
||||
productFeatureService = endpointContextStartContract.productFeaturesService;
|
||||
fleetServices = endpointContextStartContract.endpointFleetServicesFactory.asInternalUser();
|
||||
|
||||
fleetServices = createEndpointFleetServicesFactoryMock().service.asInternalUser();
|
||||
});
|
||||
|
||||
describe('and both `endpointPolicyProtections` and `endpointProtectionUpdates` is enabled', () => {
|
||||
|
@ -139,7 +142,7 @@ describe('Turn Off Policy Protections Migration', () => {
|
|||
|
||||
expect(fleetServices.packagePolicy.list as jest.Mock).toHaveBeenCalledTimes(2);
|
||||
expect(fleetServices.packagePolicy.bulkUpdate as jest.Mock).toHaveBeenCalledWith(
|
||||
fleetServices.internalSoClient,
|
||||
fleetServices.savedObjects.createInternalScopedSoClient({ readonly: false }),
|
||||
esClient,
|
||||
[
|
||||
expect.objectContaining({ id: bulkUpdateResponse.updatedPolicies![0].id }),
|
||||
|
@ -210,7 +213,7 @@ describe('Turn Off Policy Protections Migration', () => {
|
|||
|
||||
expect(fleetServices.packagePolicy.list as jest.Mock).toHaveBeenCalledTimes(2);
|
||||
expect(fleetServices.packagePolicy.bulkUpdate as jest.Mock).toHaveBeenCalledWith(
|
||||
fleetServices.internalSoClient,
|
||||
fleetServices.savedObjects.createInternalScopedSoClient({ readonly: false }),
|
||||
esClient,
|
||||
[
|
||||
expect.objectContaining({ id: bulkUpdateResponse.updatedPolicies![0].id }),
|
||||
|
@ -317,7 +320,7 @@ describe('Turn Off Policy Protections Migration', () => {
|
|||
|
||||
expect(fleetServices.packagePolicy.list as jest.Mock).toHaveBeenCalledTimes(2);
|
||||
expect(fleetServices.packagePolicy.bulkUpdate as jest.Mock).toHaveBeenCalledWith(
|
||||
fleetServices.internalSoClient,
|
||||
fleetServices.savedObjects.createInternalUnscopedSoClient(),
|
||||
esClient,
|
||||
[
|
||||
expect.objectContaining({ id: bulkUpdateResponse.updatedPolicies![0].id }),
|
||||
|
|
|
@ -62,7 +62,8 @@ export const turnOffPolicyProtectionsIfNotSupported = async (
|
|||
);
|
||||
}
|
||||
|
||||
const { packagePolicy, internalSoClient, endpointPolicyKuery } = fleetServices;
|
||||
const { packagePolicy, savedObjects, endpointPolicyKuery } = fleetServices;
|
||||
const internalSoClient = savedObjects.createInternalScopedSoClient({ readonly: false });
|
||||
const updates: UpdatePackagePolicy[] = [];
|
||||
const messages: string[] = [];
|
||||
const perPage = 1000;
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
savedObjectsClientMock,
|
||||
savedObjectsServiceMock,
|
||||
securityServiceMock,
|
||||
coreMock,
|
||||
} from '@kbn/core/server/mocks';
|
||||
import type {
|
||||
IRouter,
|
||||
|
@ -25,23 +26,20 @@ import type {
|
|||
RouteConfig,
|
||||
RouteMethod,
|
||||
SavedObjectsClientContract,
|
||||
SecurityServiceStart,
|
||||
} from '@kbn/core/server';
|
||||
import { listMock } from '@kbn/lists-plugin/server/mocks';
|
||||
import { securityMock } from '@kbn/security-plugin/server/mocks';
|
||||
import { alertsMock } from '@kbn/alerting-plugin/server/mocks';
|
||||
import { cloudMock } from '@kbn/cloud-plugin/server/mocks';
|
||||
import type { FleetStartContract } from '@kbn/fleet-plugin/server';
|
||||
import {
|
||||
createFleetActionsClientMock,
|
||||
createFleetFromHostFilesClientMock,
|
||||
createFleetStartContractMock,
|
||||
createFleetToHostFilesClientMock,
|
||||
createMessageSigningServiceMock,
|
||||
createMockAgentPolicyService,
|
||||
createMockAgentService,
|
||||
createMockPackageService,
|
||||
createPackagePolicyServiceMock,
|
||||
} from '@kbn/fleet-plugin/server/mocks';
|
||||
import { createFleetAuthzMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import type { RequestFixtureOptions, RouterMock } from '@kbn/core-http-router-server-mocks';
|
||||
import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
|
||||
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
|
||||
|
@ -49,8 +47,12 @@ import { casesPluginMock } from '@kbn/cases-plugin/server/mocks';
|
|||
import { createCasesClientMock } from '@kbn/cases-plugin/server/client/mocks';
|
||||
import type { AddVersionOpts, VersionedRouteConfig } from '@kbn/core-http-server';
|
||||
import { unsecuredActionsClientMock } from '@kbn/actions-plugin/server/unsecured_actions_client/unsecured_actions_client.mock';
|
||||
import type { PluginStartContract } from '@kbn/actions-plugin/server';
|
||||
import type { PluginStartContract as ActionPluginStartContract } from '@kbn/actions-plugin/server';
|
||||
import type { Mutable } from 'utility-types';
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
import { EndpointMetadataService } from '../services/metadata';
|
||||
import { createEndpointFleetServicesFactoryMock } from '../services/fleet/endpoint_fleet_services_factory.mocks';
|
||||
import type { ProductFeaturesService } from '../../lib/product_features_service';
|
||||
import { responseActionsClientMock } from '../services/actions/clients/mocks';
|
||||
import { getEndpointAuthzInitialStateMock } from '../../../common/endpoint/service/authz/mocks';
|
||||
import { createMockConfig, requestContextMock } from '../../lib/detection_engine/routes/__mocks__';
|
||||
|
@ -67,15 +69,13 @@ import {
|
|||
parseExperimentalConfigValue,
|
||||
} from '../../../common/experimental_features';
|
||||
import { requestContextFactoryMock } from '../../request_context_factory.mock';
|
||||
import { EndpointMetadataService } from '../services/metadata';
|
||||
import type { SecuritySolutionRequestHandlerContextMock } from '../../lib/detection_engine/routes/__mocks__/request_context';
|
||||
import { createMockClients } from '../../lib/detection_engine/routes/__mocks__/request_context';
|
||||
import { createEndpointMetadataServiceTestContextMock } from '../services/metadata/mocks';
|
||||
import type { EndpointAuthz } from '../../../common/endpoint/types/authz';
|
||||
import { EndpointFleetServicesFactory } from '../services/fleet';
|
||||
import { createLicenseServiceMock } from '../../../common/license/mocks';
|
||||
import { createFeatureUsageServiceMock } from '../services/feature_usage/mocks';
|
||||
import { createProductFeaturesServiceMock } from '../../lib/product_features_service/mocks';
|
||||
|
||||
/**
|
||||
* Creates a mocked EndpointAppContext.
|
||||
*/
|
||||
|
@ -99,7 +99,15 @@ export const createMockEndpointAppContext = (
|
|||
export const createMockEndpointAppContextService = (
|
||||
mockManifestManager?: ManifestManager
|
||||
): jest.Mocked<EndpointAppContextService> => {
|
||||
const mockEndpointMetadataContext = createEndpointMetadataServiceTestContextMock();
|
||||
const { esClient, fleetStartServices } = createMockEndpointAppContextServiceStartContract();
|
||||
const fleetServices = createEndpointFleetServicesFactoryMock({
|
||||
fleetDependencies: fleetStartServices,
|
||||
}).service.asInternalUser();
|
||||
const endpointMetadataService = new EndpointMetadataService(
|
||||
esClient,
|
||||
savedObjectsClientMock.create(),
|
||||
fleetServices
|
||||
);
|
||||
const casesClientMock = createCasesClientMock();
|
||||
const fleetFromHostFilesClientMock = createFleetFromHostFilesClientMock();
|
||||
const fleetToHostFilesClientMock = createFleetToHostFilesClientMock();
|
||||
|
@ -117,8 +125,8 @@ export const createMockEndpointAppContextService = (
|
|||
},
|
||||
createLogger: jest.fn((...parts) => loggerFactory.get(...parts)),
|
||||
getManifestManager: jest.fn().mockReturnValue(mockManifestManager ?? jest.fn()),
|
||||
getEndpointMetadataService: jest.fn(() => mockEndpointMetadataContext.endpointMetadataService),
|
||||
getInternalFleetServices: jest.fn(() => mockEndpointMetadataContext.fleetServices),
|
||||
getEndpointMetadataService: jest.fn(() => endpointMetadataService),
|
||||
getInternalFleetServices: jest.fn(() => fleetServices),
|
||||
getEndpointAuthz: jest.fn(async (_) => getEndpointAuthzInitialStateMock()),
|
||||
getCasesClient: jest.fn().mockReturnValue(casesClientMock),
|
||||
getFleetFromHostFilesClient: jest.fn(async () => fleetFromHostFilesClientMock),
|
||||
|
@ -146,6 +154,7 @@ export const createMockEndpointAppContextServiceSetupContract =
|
|||
cloud: cloudMock.createSetup(),
|
||||
loggerFactory: loggingSystemMock.create(),
|
||||
telemetry: analyticsServiceMock.createAnalyticsServiceSetup(),
|
||||
httpServiceSetup: coreMock.createSetup().http,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -153,38 +162,13 @@ export const createMockEndpointAppContextServiceSetupContract =
|
|||
* Creates a mocked input contract for the `EndpointAppContextService#start()` method
|
||||
*/
|
||||
export const createMockEndpointAppContextServiceStartContract =
|
||||
(): jest.Mocked<EndpointAppContextServiceStartContract> => {
|
||||
(): DeeplyMockedKeys<EndpointAppContextServiceStartContract> => {
|
||||
const config = createMockConfig();
|
||||
|
||||
const logger = loggingSystemMock.create().get('mock_endpoint_app_context');
|
||||
const savedObjectsStart = savedObjectsServiceMock.createStartContract();
|
||||
const security = securityServiceMock.createStart();
|
||||
const agentService = createMockAgentService();
|
||||
const agentPolicyService = createMockAgentPolicyService();
|
||||
const security =
|
||||
securityServiceMock.createStart() as unknown as DeeplyMockedKeys<SecurityServiceStart>;
|
||||
const packagePolicyService = createPackagePolicyServiceMock();
|
||||
const packageService = createMockPackageService();
|
||||
const endpointMetadataService = new EndpointMetadataService(
|
||||
savedObjectsStart,
|
||||
agentPolicyService,
|
||||
packagePolicyService,
|
||||
logger
|
||||
);
|
||||
const endpointFleetServicesFactory = new EndpointFleetServicesFactory(
|
||||
{
|
||||
packageService,
|
||||
packagePolicyService,
|
||||
agentPolicyService,
|
||||
agentService,
|
||||
},
|
||||
savedObjectsStart
|
||||
);
|
||||
const experimentalFeatures = config.experimentalFeatures;
|
||||
const productFeaturesService = createProductFeaturesServiceMock(
|
||||
undefined,
|
||||
experimentalFeatures,
|
||||
undefined,
|
||||
logger
|
||||
);
|
||||
|
||||
packagePolicyService.list.mockImplementation(async (_, options) => {
|
||||
return {
|
||||
|
@ -200,47 +184,32 @@ export const createMockEndpointAppContextServiceStartContract =
|
|||
securityMock.createMockAuthenticatedUser({ roles: ['superuser'] })
|
||||
);
|
||||
|
||||
const casesMock = casesPluginMock.createStartContract();
|
||||
const fleetActionsClientMock = createFleetActionsClientMock();
|
||||
|
||||
return {
|
||||
endpointMetadataService,
|
||||
endpointFleetServicesFactory,
|
||||
logger,
|
||||
fleetAuthzService: createFleetAuthzServiceMock(),
|
||||
createFleetFilesClient: {
|
||||
fromHost: jest.fn((..._) => createFleetFromHostFilesClientMock()),
|
||||
toHost: jest.fn((..._) => createFleetToHostFilesClientMock()),
|
||||
},
|
||||
manifestManager: getManifestManagerMock(),
|
||||
const startContract: DeeplyMockedKeys<EndpointAppContextServiceStartContract> = {
|
||||
security,
|
||||
alerting: alertsMock.createStart(),
|
||||
config,
|
||||
productFeaturesService: createProductFeaturesServiceMock(
|
||||
undefined,
|
||||
config.experimentalFeatures,
|
||||
undefined,
|
||||
logger
|
||||
) as DeeplyMockedKeys<ProductFeaturesService>,
|
||||
experimentalFeatures: config.experimentalFeatures,
|
||||
fleetStartServices: createFleetStartContractMock(),
|
||||
cases: casesPluginMock.createStartContract(),
|
||||
manifestManager: getManifestManagerMock() as DeeplyMockedKeys<ManifestManager>,
|
||||
alerting: alertsMock.createStart(),
|
||||
licenseService: createLicenseServiceMock(),
|
||||
registerIngestCallback: jest.fn<
|
||||
ReturnType<FleetStartContract['registerExternalCallback']>,
|
||||
Parameters<FleetStartContract['registerExternalCallback']>
|
||||
>(),
|
||||
exceptionListsClient: listMock.getExceptionListClient(),
|
||||
cases: casesMock,
|
||||
featureUsageService: createFeatureUsageServiceMock(),
|
||||
experimentalFeatures,
|
||||
messageSigningService: createMessageSigningServiceMock(),
|
||||
createFleetActionsClient: jest.fn((_) => fleetActionsClientMock),
|
||||
esClient: elasticsearchClientMock.createElasticsearchClient(),
|
||||
productFeaturesService,
|
||||
savedObjectsClient: savedObjectsClientMock.create(),
|
||||
savedObjectsServiceStart: savedObjectsServiceMock.createStartContract(),
|
||||
connectorActions: {
|
||||
getUnsecuredActionsClient: jest.fn().mockReturnValue(unsecuredActionsClientMock.create()),
|
||||
} as unknown as jest.Mocked<PluginStartContract>,
|
||||
} as unknown as jest.Mocked<ActionPluginStartContract>,
|
||||
};
|
||||
};
|
||||
|
||||
export const createFleetAuthzServiceMock = (): jest.Mocked<FleetStartContract['authz']> => {
|
||||
return {
|
||||
fromRequest: jest.fn(async (_) => createFleetAuthzMock()),
|
||||
return startContract;
|
||||
};
|
||||
};
|
||||
|
||||
export function createRouteHandlerContext(
|
||||
dataClient: ScopedClusterClientMock,
|
||||
|
|
|
@ -142,7 +142,9 @@ describe('Response actions', () => {
|
|||
const routerMock = httpServiceMock.createRouter();
|
||||
mockResponse = httpServerMock.createResponseFactory();
|
||||
const startContract = createMockEndpointAppContextServiceStartContract();
|
||||
(startContract.messageSigningService?.sign as jest.Mock).mockImplementation(() => {
|
||||
(
|
||||
startContract.fleetStartServices.messageSigningService?.sign as jest.Mock
|
||||
).mockImplementation(() => {
|
||||
return {
|
||||
data: 'thisisthedata',
|
||||
signature: 'thisisasignature',
|
||||
|
@ -163,6 +165,7 @@ describe('Response actions', () => {
|
|||
endpointAppContextService.setup(createMockEndpointAppContextServiceSetupContract());
|
||||
endpointAppContextService.start({
|
||||
...startContract,
|
||||
esClient: mockScopedClient.asInternalUser,
|
||||
licenseService,
|
||||
});
|
||||
|
||||
|
|
|
@ -46,17 +46,9 @@ export function getMetadataListRequestHandler(
|
|||
> {
|
||||
return async (context, request, response) => {
|
||||
const endpointMetadataService = endpointAppContext.service.getEndpointMetadataService();
|
||||
const fleetServices = endpointAppContext.service.getInternalFleetServices();
|
||||
const esClient = (await context.core).elasticsearch.client.asInternalUser;
|
||||
const soClient = (await context.core).savedObjects.client;
|
||||
|
||||
try {
|
||||
const { data, total } = await endpointMetadataService.getHostMetadataList(
|
||||
esClient,
|
||||
soClient,
|
||||
fleetServices,
|
||||
request.query
|
||||
);
|
||||
const { data, total } = await endpointMetadataService.getHostMetadataList(request.query);
|
||||
|
||||
const body: MetadataListResponse = {
|
||||
data,
|
||||
|
@ -88,13 +80,8 @@ export const getMetadataRequestHandler = function (
|
|||
const endpointMetadataService = endpointAppContext.service.getEndpointMetadataService();
|
||||
|
||||
try {
|
||||
const esClient = (await context.core).elasticsearch.client;
|
||||
return response.ok({
|
||||
body: await endpointMetadataService.getEnrichedHostMetadata(
|
||||
esClient.asInternalUser,
|
||||
endpointAppContext.service.getInternalFleetServices(),
|
||||
request.params.id
|
||||
),
|
||||
body: await endpointMetadataService.getEnrichedHostMetadata(request.params.id),
|
||||
});
|
||||
} catch (error) {
|
||||
return errorHandler(logger, response, error);
|
||||
|
|
|
@ -94,8 +94,7 @@ describe('test endpoint routes', () => {
|
|||
startContract = createMockEndpointAppContextServiceStartContract();
|
||||
|
||||
(
|
||||
startContract.endpointFleetServicesFactory.asInternalUser()
|
||||
.packagePolicy as jest.Mocked<PackagePolicyClient>
|
||||
startContract.fleetStartServices.packagePolicyService as jest.Mocked<PackagePolicyClient>
|
||||
).list.mockImplementation(() => {
|
||||
return Promise.resolve({
|
||||
items: [],
|
||||
|
@ -107,11 +106,14 @@ describe('test endpoint routes', () => {
|
|||
|
||||
endpointAppContextService = new EndpointAppContextService();
|
||||
endpointAppContextService.setup(createMockEndpointAppContextServiceSetupContract());
|
||||
endpointAppContextService.start({ ...startContract });
|
||||
mockAgentClient = startContract.endpointFleetServicesFactory.asInternalUser()
|
||||
.agent as jest.Mocked<AgentClient>;
|
||||
mockAgentPolicyService = startContract.endpointFleetServicesFactory.asInternalUser()
|
||||
.agentPolicy as jest.Mocked<AgentPolicyServiceInterface>;
|
||||
endpointAppContextService.start({
|
||||
...startContract,
|
||||
esClient: mockScopedClient.asInternalUser,
|
||||
});
|
||||
mockAgentClient = startContract.fleetStartServices.agentService
|
||||
.asInternalUser as jest.Mocked<AgentClient>;
|
||||
mockAgentPolicyService = startContract.fleetStartServices
|
||||
.agentPolicyService as jest.Mocked<AgentPolicyServiceInterface>;
|
||||
|
||||
registerEndpointRoutes(routerMock, {
|
||||
...createMockEndpointAppContext(),
|
||||
|
|
|
@ -73,7 +73,7 @@ export class EndpointActionsClient extends ResponseActionsClientImpl {
|
|||
const uniqueIds = [...new Set(ids)];
|
||||
const foundEndpointHosts = await this.options.endpointService
|
||||
.getEndpointMetadataService()
|
||||
.getMetadataForEndpoints(this.options.esClient, uniqueIds);
|
||||
.getMetadataForEndpoints(uniqueIds);
|
||||
const validIds = foundEndpointHosts.map((endpoint: HostMetadata) => endpoint.elastic.agent.id);
|
||||
const invalidIds = ids.filter((id) => !validIds.includes(id));
|
||||
|
||||
|
|
|
@ -106,7 +106,10 @@ const createConstructorOptionsMock = (): Required<ResponseActionsClientOptionsMo
|
|||
);
|
||||
|
||||
endpointService.setup(createMockEndpointAppContextServiceSetupContract());
|
||||
endpointService.start(createMockEndpointAppContextServiceStartContract());
|
||||
endpointService.start({
|
||||
...createMockEndpointAppContextServiceStartContract(),
|
||||
esClient,
|
||||
});
|
||||
|
||||
return {
|
||||
esClient,
|
||||
|
|
|
@ -85,7 +85,7 @@ export const getPendingActionsSummary = async (
|
|||
// If the metadata documents for all agents has not yet been retrieved, do it now
|
||||
if (!endpointMetadataLastUpdated) {
|
||||
endpointMetadataLastUpdated = (
|
||||
await metadataService.findHostMetadataForFleetAgents(esClient, agentIDs)
|
||||
await metadataService.findHostMetadataForFleetAgents(agentIDs)
|
||||
).reduce((acc, endpointMetadata) => {
|
||||
acc[endpointMetadata.elastic.agent.id] = new Date(endpointMetadata.event.created);
|
||||
return acc;
|
||||
|
|
|
@ -550,9 +550,7 @@ export const getAgentHostNamesWithIds = async ({
|
|||
metadataService: EndpointMetadataService;
|
||||
}): Promise<{ [id: string]: string }> => {
|
||||
// get host metadata docs with queried agents
|
||||
const metaDataDocs = await metadataService.findHostMetadataForFleetAgents(esClient, [
|
||||
...new Set(agentIds),
|
||||
]);
|
||||
const metaDataDocs = await metadataService.findHostMetadataForFleetAgents([...new Set(agentIds)]);
|
||||
// agent ids and names from metadata
|
||||
// map this into an object as {id1: name1, id2: name2} etc
|
||||
const agentsMetadataInfo = agentIds.reduce<{ [id: string]: string }>((acc, id) => {
|
||||
|
|
|
@ -18,21 +18,15 @@ export class EndpointAgentStatusClient extends AgentStatusClient {
|
|||
async getAgentStatuses(agentIds: string[]): Promise<AgentStatusRecords> {
|
||||
const metadataService = this.options.endpointService.getEndpointMetadataService();
|
||||
const esClient = this.options.esClient;
|
||||
const soClient = this.options.soClient;
|
||||
|
||||
try {
|
||||
const agentIdsKql = agentIds.map((agentId) => `agent.id: ${agentId}`).join(' or ');
|
||||
const [{ data: hostInfoForAgents }, allPendingActions] = await Promise.all([
|
||||
metadataService.getHostMetadataList(
|
||||
esClient,
|
||||
soClient,
|
||||
this.options.endpointService.getInternalFleetServices(),
|
||||
{
|
||||
page: 0,
|
||||
pageSize: 1000,
|
||||
kuery: agentIdsKql,
|
||||
}
|
||||
),
|
||||
metadataService.getHostMetadataList({
|
||||
page: 0,
|
||||
pageSize: 1000,
|
||||
kuery: agentIdsKql,
|
||||
}),
|
||||
getPendingActionsSummary(esClient, metadataService, this.log, agentIds),
|
||||
]).catch(catchAndWrapError);
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
import type { FleetStartContract } from '@kbn/fleet-plugin/server';
|
||||
import { createFleetStartContractMock } from '@kbn/fleet-plugin/server/mocks';
|
||||
import type { SavedObjectsClientFactory } from '../saved_objects';
|
||||
import type { EndpointFleetServicesFactoryInterface } from './endpoint_fleet_services_factory';
|
||||
import { EndpointFleetServicesFactory } from './endpoint_fleet_services_factory';
|
||||
import { createSavedObjectsClientFactoryMock } from '../saved_objects/saved_objects_client_factory.mocks';
|
||||
|
||||
interface EndpointFleetServicesFactoryInterfaceMocked
|
||||
extends EndpointFleetServicesFactoryInterface {
|
||||
asInternalUser: () => DeeplyMockedKeys<
|
||||
ReturnType<EndpointFleetServicesFactoryInterface['asInternalUser']>
|
||||
>;
|
||||
}
|
||||
|
||||
interface CreateEndpointFleetServicesFactoryMockOptions {
|
||||
fleetDependencies: DeeplyMockedKeys<FleetStartContract>;
|
||||
savedObjects: SavedObjectsClientFactory;
|
||||
}
|
||||
|
||||
export const createEndpointFleetServicesFactoryMock = (
|
||||
dependencies: Partial<CreateEndpointFleetServicesFactoryMockOptions> = {}
|
||||
): {
|
||||
service: EndpointFleetServicesFactoryInterfaceMocked;
|
||||
dependencies: CreateEndpointFleetServicesFactoryMockOptions;
|
||||
} => {
|
||||
const {
|
||||
fleetDependencies = createFleetStartContractMock(),
|
||||
savedObjects = createSavedObjectsClientFactoryMock().service,
|
||||
} = dependencies;
|
||||
|
||||
return {
|
||||
service: new EndpointFleetServicesFactory(
|
||||
fleetDependencies,
|
||||
savedObjects
|
||||
) as unknown as EndpointFleetServicesFactoryInterfaceMocked,
|
||||
dependencies: { fleetDependencies, savedObjects },
|
||||
};
|
||||
};
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SavedObjectsClientContract, SavedObjectsServiceStart } from '@kbn/core/server';
|
||||
import type {
|
||||
AgentClient,
|
||||
AgentPolicyServiceInterface,
|
||||
|
@ -14,43 +13,7 @@ import type {
|
|||
PackageClient,
|
||||
} from '@kbn/fleet-plugin/server';
|
||||
import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common';
|
||||
import { createInternalSoClient } from '../../utils/create_internal_so_client';
|
||||
import { createInternalReadonlySoClient } from '../../utils/create_internal_readonly_so_client';
|
||||
|
||||
export interface EndpointFleetServicesFactoryInterface {
|
||||
asInternalUser(): EndpointInternalFleetServicesInterface;
|
||||
}
|
||||
|
||||
export class EndpointFleetServicesFactory implements EndpointFleetServicesFactoryInterface {
|
||||
constructor(
|
||||
private readonly fleetDependencies: Pick<
|
||||
FleetStartContract,
|
||||
'agentService' | 'packageService' | 'packagePolicyService' | 'agentPolicyService'
|
||||
>,
|
||||
private savedObjectsStart: SavedObjectsServiceStart
|
||||
) {}
|
||||
|
||||
asInternalUser(): EndpointInternalFleetServicesInterface {
|
||||
const {
|
||||
agentPolicyService: agentPolicy,
|
||||
packagePolicyService: packagePolicy,
|
||||
agentService,
|
||||
packageService,
|
||||
} = this.fleetDependencies;
|
||||
|
||||
return {
|
||||
agent: agentService.asInternalUser,
|
||||
agentPolicy,
|
||||
packages: packageService.asInternalUser,
|
||||
packagePolicy,
|
||||
|
||||
endpointPolicyKuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: "endpoint"`,
|
||||
|
||||
internalReadonlySoClient: createInternalReadonlySoClient(this.savedObjectsStart),
|
||||
internalSoClient: createInternalSoClient(this.savedObjectsStart),
|
||||
};
|
||||
}
|
||||
}
|
||||
import type { SavedObjectsClientFactory } from '../saved_objects';
|
||||
|
||||
/**
|
||||
* The set of Fleet services used by Endpoint
|
||||
|
@ -65,11 +28,40 @@ export interface EndpointFleetServicesInterface {
|
|||
}
|
||||
|
||||
export interface EndpointInternalFleetServicesInterface extends EndpointFleetServicesInterface {
|
||||
/**
|
||||
* An internal SO client (readonly) that can be used with the Fleet services that require it
|
||||
*/
|
||||
internalReadonlySoClient: SavedObjectsClientContract;
|
||||
|
||||
/** Internal SO client. USE ONLY WHEN ABSOLUTELY NEEDED. Else, use the `internalReadonlySoClient` */
|
||||
internalSoClient: SavedObjectsClientContract;
|
||||
savedObjects: SavedObjectsClientFactory;
|
||||
}
|
||||
|
||||
export interface EndpointFleetServicesFactoryInterface {
|
||||
asInternalUser(): EndpointInternalFleetServicesInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides centralized way to get all services for Fleet and access internal saved object clients
|
||||
*/
|
||||
export class EndpointFleetServicesFactory implements EndpointFleetServicesFactoryInterface {
|
||||
constructor(
|
||||
private readonly fleetDependencies: FleetStartContract,
|
||||
private readonly savedObjects: SavedObjectsClientFactory
|
||||
) {}
|
||||
|
||||
asInternalUser(): EndpointInternalFleetServicesInterface {
|
||||
const {
|
||||
agentPolicyService: agentPolicy,
|
||||
packagePolicyService: packagePolicy,
|
||||
agentService,
|
||||
packageService,
|
||||
} = this.fleetDependencies;
|
||||
|
||||
return {
|
||||
agent: agentService.asInternalUser,
|
||||
agentPolicy,
|
||||
|
||||
packages: packageService.asInternalUser,
|
||||
packagePolicy,
|
||||
|
||||
endpointPolicyKuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: "endpoint"`,
|
||||
|
||||
savedObjects: this.savedObjects,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { uniq } from 'lodash';
|
||||
import type { EndpointMetadataServiceTestContextMock } from './mocks';
|
||||
import { createEndpointMetadataServiceTestContextMock } from './mocks';
|
||||
import { elasticsearchServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
|
||||
import {
|
||||
legacyMetadataSearchResponseMock,
|
||||
|
@ -37,7 +37,7 @@ describe('EndpointMetadataService', () => {
|
|||
endpointDocGenerator = new EndpointDocGenerator('seed');
|
||||
testMockedContext = createEndpointMetadataServiceTestContextMock();
|
||||
metadataService = testMockedContext.endpointMetadataService;
|
||||
esClient = elasticsearchServiceMock.createScopedClusterClient().asInternalUser;
|
||||
esClient = testMockedContext.esClient;
|
||||
soClient = savedObjectsClientMock.create();
|
||||
soClient.find = jest.fn().mockResolvedValue({ saved_objects: [] });
|
||||
fleetAppContextService.start(
|
||||
|
@ -58,7 +58,7 @@ describe('EndpointMetadataService', () => {
|
|||
});
|
||||
|
||||
it('should call elasticsearch with proper filter', async () => {
|
||||
await metadataService.findHostMetadataForFleetAgents(esClient, fleetAgentIds);
|
||||
await metadataService.findHostMetadataForFleetAgents(fleetAgentIds);
|
||||
expect(esClient.search).toHaveBeenCalledWith(
|
||||
{ ...getESQueryHostMetadataByFleetAgentIds(fleetAgentIds), size: fleetAgentIds.length },
|
||||
{ ignore: [404] }
|
||||
|
@ -67,16 +67,13 @@ describe('EndpointMetadataService', () => {
|
|||
|
||||
it('should throw a wrapped elasticsearch Error when one occurs', async () => {
|
||||
esClient.search.mockRejectedValue(new Error('foo bar'));
|
||||
await expect(
|
||||
metadataService.findHostMetadataForFleetAgents(esClient, fleetAgentIds)
|
||||
).rejects.toThrow(EndpointError);
|
||||
await expect(metadataService.findHostMetadataForFleetAgents(fleetAgentIds)).rejects.toThrow(
|
||||
EndpointError
|
||||
);
|
||||
});
|
||||
|
||||
it('should return an array of Host Metadata documents', async () => {
|
||||
const response = await metadataService.findHostMetadataForFleetAgents(
|
||||
esClient,
|
||||
fleetAgentIds
|
||||
);
|
||||
const response = await metadataService.findHostMetadataForFleetAgents(fleetAgentIds);
|
||||
expect(response).toEqual([endpointMetadataDoc]);
|
||||
});
|
||||
});
|
||||
|
@ -86,22 +83,16 @@ describe('EndpointMetadataService', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
agentPolicyServiceMock = testMockedContext.agentPolicyService;
|
||||
esClient = elasticsearchServiceMock.createScopedClusterClient().asInternalUser;
|
||||
});
|
||||
|
||||
it('should throw wrapped error if es error', async () => {
|
||||
esClient.search.mockRejectedValue({});
|
||||
const metadataListResponse = metadataService.getHostMetadataList(
|
||||
esClient,
|
||||
soClient,
|
||||
testMockedContext.fleetServices,
|
||||
{
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
kuery: '',
|
||||
hostStatuses: [],
|
||||
}
|
||||
);
|
||||
const metadataListResponse = metadataService.getHostMetadataList({
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
kuery: '',
|
||||
hostStatuses: [],
|
||||
});
|
||||
await expect(metadataListResponse).rejects.toThrow(EndpointError);
|
||||
});
|
||||
|
||||
|
@ -109,17 +100,12 @@ describe('EndpointMetadataService', () => {
|
|||
esClient.search.mockRejectedValue({
|
||||
meta: { body: { error: { type: 'index_not_found_exception' } } },
|
||||
});
|
||||
const metadataListResponse = await metadataService.getHostMetadataList(
|
||||
esClient,
|
||||
soClient,
|
||||
testMockedContext.fleetServices,
|
||||
{
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
kuery: '',
|
||||
hostStatuses: [],
|
||||
}
|
||||
);
|
||||
const metadataListResponse = await metadataService.getHostMetadataList({
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
kuery: '',
|
||||
hostStatuses: [],
|
||||
});
|
||||
|
||||
expect(metadataListResponse).toEqual({
|
||||
data: [],
|
||||
|
@ -156,30 +142,23 @@ describe('EndpointMetadataService', () => {
|
|||
const mockDoc = unitedMetadataSearchResponseMock(endpointMetadataDoc, mockAgent);
|
||||
esClient.search.mockResponse(mockDoc);
|
||||
agentPolicyServiceMock.getByIds.mockResolvedValue(agentPolicies);
|
||||
testMockedContext.packagePolicyService.list.mockImplementation(
|
||||
async (_, { page, perPage }) => {
|
||||
const response = {
|
||||
items: packagePolicies,
|
||||
page: page ?? 1,
|
||||
total: packagePolicies.length,
|
||||
perPage: packagePolicies.length,
|
||||
};
|
||||
testMockedContext.packagePolicyService.list.mockImplementation(async (_, { page }) => {
|
||||
const response = {
|
||||
items: packagePolicies,
|
||||
page: page ?? 1,
|
||||
total: packagePolicies.length,
|
||||
perPage: packagePolicies.length,
|
||||
};
|
||||
|
||||
if ((page ?? 1) > 1) {
|
||||
response.items = [];
|
||||
}
|
||||
|
||||
return response;
|
||||
if ((page ?? 1) > 1) {
|
||||
response.items = [];
|
||||
}
|
||||
);
|
||||
|
||||
return response;
|
||||
});
|
||||
|
||||
const queryOptions = { page: 1, pageSize: 10, kuery: '', hostStatuses: [] };
|
||||
const metadataListResponse = await metadataService.getHostMetadataList(
|
||||
esClient,
|
||||
soClient,
|
||||
testMockedContext.fleetServices,
|
||||
queryOptions
|
||||
);
|
||||
const metadataListResponse = await metadataService.getHostMetadataList(queryOptions);
|
||||
const unitedIndexQuery = await buildUnitedIndexQuery(
|
||||
soClient,
|
||||
queryOptions,
|
||||
|
|
|
@ -5,16 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { uniq } from 'lodash';
|
||||
import type {
|
||||
ElasticsearchClient,
|
||||
Logger,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsServiceStart,
|
||||
} from '@kbn/core/server';
|
||||
import type { ElasticsearchClient, Logger, SavedObjectsClientContract } from '@kbn/core/server';
|
||||
|
||||
import type { SearchResponse, SearchTotalHits } from '@elastic/elasticsearch/lib/api/types';
|
||||
import type { Agent, AgentPolicy, PackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import type { AgentPolicyServiceInterface, PackagePolicyClient } from '@kbn/fleet-plugin/server';
|
||||
import { AgentNotFoundError } from '@kbn/fleet-plugin/server';
|
||||
import type {
|
||||
HostInfo,
|
||||
|
@ -48,7 +42,6 @@ import {
|
|||
fleetAgentStatusToEndpointHostStatus,
|
||||
wrapErrorIfNeeded,
|
||||
} from '../../utils';
|
||||
import { createInternalReadonlySoClient } from '../../utils/create_internal_readonly_so_client';
|
||||
import { getAllEndpointPackagePolicies } from '../../routes/metadata/support/endpoint_package_policies';
|
||||
import type { GetMetadataListRequestQuery } from '../../../../common/api/endpoint';
|
||||
import { EndpointError } from '../../../../common/endpoint/errors';
|
||||
|
@ -65,52 +58,25 @@ const isAgentPolicyWithPackagePolicies = (
|
|||
};
|
||||
|
||||
export class EndpointMetadataService {
|
||||
/**
|
||||
* For internal use only by the `this.DANGEROUS_INTERNAL_SO_CLIENT`
|
||||
* @deprecated
|
||||
*/
|
||||
private __DANGEROUS_INTERNAL_SO_CLIENT: SavedObjectsClientContract | undefined;
|
||||
|
||||
constructor(
|
||||
private savedObjectsStart: SavedObjectsServiceStart,
|
||||
private readonly agentPolicyService: AgentPolicyServiceInterface,
|
||||
private readonly packagePolicyService: PackagePolicyClient,
|
||||
private readonly esClient: ElasticsearchClient,
|
||||
private readonly soClient: SavedObjectsClientContract,
|
||||
private readonly fleetServices: EndpointFleetServicesInterface,
|
||||
private readonly logger?: Logger
|
||||
) {}
|
||||
|
||||
/**
|
||||
* An INTERNAL Saved Object client that is effectively the system user and has all privileges and permissions and
|
||||
* can access any saved object. Used primarly to retrieve fleet data for endpoint enrichment (so that users are
|
||||
* not required to have superuser role)
|
||||
*
|
||||
* **IMPORTANT: SHOULD BE USED ONLY FOR READ-ONLY ACCESS AND WITH DISCRETION**
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private get DANGEROUS_INTERNAL_SO_CLIENT() {
|
||||
// The INTERNAL SO client must be created during the first time its used. This is because creating it during
|
||||
// instance initialization (in `constructor(){}`) causes the SO Client to be invalid (perhaps because this
|
||||
// instantiation is happening during the plugin's the start phase)
|
||||
if (!this.__DANGEROUS_INTERNAL_SO_CLIENT) {
|
||||
this.__DANGEROUS_INTERNAL_SO_CLIENT = createInternalReadonlySoClient(this.savedObjectsStart);
|
||||
}
|
||||
|
||||
return this.__DANGEROUS_INTERNAL_SO_CLIENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single endpoint host metadata. Note that the return endpoint document, if found,
|
||||
* could be associated with a Fleet Agent that is no longer active. If wanting to ensure the
|
||||
* endpoint is associated with an active Fleet Agent, then use `getEnrichedHostMetadata()` instead
|
||||
*
|
||||
* @param esClient Elasticsearch Client (usually scoped to the user's context)
|
||||
* @param endpointId the endpoint id (from `agent.id`)
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
async getHostMetadata(esClient: ElasticsearchClient, endpointId: string): Promise<HostMetadata> {
|
||||
async getHostMetadata(endpointId: string): Promise<HostMetadata> {
|
||||
const query = getESQueryHostMetadataByID(endpointId);
|
||||
const queryResult = await esClient.search<HostMetadata>(query).catch(catchAndWrapError);
|
||||
const queryResult = await this.esClient.search<HostMetadata>(query).catch(catchAndWrapError);
|
||||
const endpointMetadata = queryResponseToHostResult(queryResult).result;
|
||||
|
||||
if (endpointMetadata) {
|
||||
|
@ -122,19 +88,15 @@ export class EndpointMetadataService {
|
|||
|
||||
/**
|
||||
* Find a list of Endpoint Host Metadata document associated with a given list of Fleet Agent Ids
|
||||
* @param esClient
|
||||
* @param fleetAgentIds
|
||||
*/
|
||||
async findHostMetadataForFleetAgents(
|
||||
esClient: ElasticsearchClient,
|
||||
fleetAgentIds: string[]
|
||||
): Promise<HostMetadata[]> {
|
||||
async findHostMetadataForFleetAgents(fleetAgentIds: string[]): Promise<HostMetadata[]> {
|
||||
const query = getESQueryHostMetadataByFleetAgentIds(fleetAgentIds);
|
||||
|
||||
// @ts-expect-error `size` not defined as top level property when using `typesWithBodyKey`
|
||||
query.size = fleetAgentIds.length;
|
||||
|
||||
const searchResult = await esClient
|
||||
const searchResult = await this.esClient
|
||||
.search<HostMetadata>(query, { ignore: [404] })
|
||||
.catch(catchAndWrapError);
|
||||
|
||||
|
@ -144,18 +106,12 @@ export class EndpointMetadataService {
|
|||
/**
|
||||
* Retrieve a single endpoint host metadata along with fleet information
|
||||
*
|
||||
* @param esClient Elasticsearch Client (usually scoped to the user's context)
|
||||
* @param fleetServices
|
||||
* @param endpointId the endpoint id (from `agent.id`)
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
async getEnrichedHostMetadata(
|
||||
esClient: ElasticsearchClient,
|
||||
fleetServices: EndpointFleetServicesInterface,
|
||||
endpointId: string
|
||||
): Promise<HostInfo> {
|
||||
const endpointMetadata = await this.getHostMetadata(esClient, endpointId);
|
||||
async getEnrichedHostMetadata(endpointId: string): Promise<HostInfo> {
|
||||
const endpointMetadata = await this.getHostMetadata(endpointId);
|
||||
|
||||
let fleetAgentId = endpointMetadata.elastic.agent.id;
|
||||
let fleetAgent: Agent | undefined;
|
||||
|
@ -167,7 +123,7 @@ export class EndpointMetadataService {
|
|||
this.logger?.warn(`Missing elastic agent id, using host id instead ${fleetAgentId}`);
|
||||
}
|
||||
|
||||
fleetAgent = await this.getFleetAgent(fleetServices.agent, fleetAgentId);
|
||||
fleetAgent = await this.getFleetAgent(fleetAgentId);
|
||||
} catch (error) {
|
||||
if (error instanceof FleetAgentNotFoundError) {
|
||||
this.logger?.debug(`agent with id ${fleetAgentId} not found`);
|
||||
|
@ -183,12 +139,12 @@ export class EndpointMetadataService {
|
|||
);
|
||||
}
|
||||
|
||||
return this.enrichHostMetadata(fleetServices, endpointMetadata, fleetAgent);
|
||||
return this.enrichHostMetadata(endpointMetadata, fleetAgent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enriches a host metadata document with data from fleet
|
||||
* @param fleetServices
|
||||
*
|
||||
* @param endpointMetadata
|
||||
* @param _fleetAgent
|
||||
* @param _fleetAgentPolicy
|
||||
|
@ -197,7 +153,6 @@ export class EndpointMetadataService {
|
|||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
private async enrichHostMetadata(
|
||||
fleetServices: EndpointFleetServicesInterface,
|
||||
endpointMetadata: HostMetadata,
|
||||
/**
|
||||
* If undefined, it will be retrieved from Fleet using the ID in the endpointMetadata.
|
||||
|
@ -233,7 +188,7 @@ export class EndpointMetadataService {
|
|||
);
|
||||
}
|
||||
|
||||
fleetAgent = await this.getFleetAgent(fleetServices.agent, fleetAgentId);
|
||||
fleetAgent = await this.getFleetAgent(fleetAgentId);
|
||||
} catch (error) {
|
||||
if (error instanceof FleetAgentNotFoundError) {
|
||||
this.logger?.warn(`Agent with id ${fleetAgentId} not found`);
|
||||
|
@ -302,15 +257,11 @@ export class EndpointMetadataService {
|
|||
/**
|
||||
* Retrieve a single Fleet Agent data
|
||||
*
|
||||
* @param fleetAgentService
|
||||
* @param agentId The elastic agent id (`from `elastic.agent.id`)
|
||||
*/
|
||||
async getFleetAgent(
|
||||
fleetAgentService: EndpointFleetServicesInterface['agent'],
|
||||
agentId: string
|
||||
): Promise<Agent> {
|
||||
async getFleetAgent(agentId: string): Promise<Agent> {
|
||||
try {
|
||||
return await fleetAgentService.getAgent(agentId);
|
||||
return await this.fleetServices.agent.getAgent(agentId);
|
||||
} catch (error) {
|
||||
if (error instanceof AgentNotFoundError) {
|
||||
throw new FleetAgentNotFoundError(`agent with id ${agentId} not found`, error);
|
||||
|
@ -328,8 +279,8 @@ export class EndpointMetadataService {
|
|||
* @throws
|
||||
*/
|
||||
async getFleetAgentPolicy(agentPolicyId: string): Promise<AgentPolicyWithPackagePolicies> {
|
||||
const agentPolicy = await this.agentPolicyService
|
||||
.get(this.DANGEROUS_INTERNAL_SO_CLIENT, agentPolicyId, true)
|
||||
const agentPolicy = await this.fleetServices.agentPolicy
|
||||
.get(this.soClient, agentPolicyId, true)
|
||||
.catch(catchAndWrapError);
|
||||
|
||||
if (agentPolicy) {
|
||||
|
@ -347,8 +298,8 @@ export class EndpointMetadataService {
|
|||
* @throws
|
||||
*/
|
||||
async getFleetEndpointPackagePolicy(endpointPolicyId: string): Promise<PolicyData> {
|
||||
const endpointPackagePolicy = await this.packagePolicyService
|
||||
.get(this.DANGEROUS_INTERNAL_SO_CLIENT, endpointPolicyId)
|
||||
const endpointPackagePolicy = await this.fleetServices.packagePolicy
|
||||
.get(this.soClient, endpointPolicyId)
|
||||
.catch(catchAndWrapError);
|
||||
|
||||
if (!endpointPackagePolicy) {
|
||||
|
@ -363,27 +314,25 @@ export class EndpointMetadataService {
|
|||
/**
|
||||
* Retrieve list of host metadata. Only supports new united index.
|
||||
*
|
||||
* @param esClient
|
||||
* @param queryOptions
|
||||
* @param soClient
|
||||
* @param fleetServices
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
async getHostMetadataList(
|
||||
esClient: ElasticsearchClient,
|
||||
soClient: SavedObjectsClientContract,
|
||||
fleetServices: EndpointFleetServicesInterface,
|
||||
queryOptions: GetMetadataListRequestQuery
|
||||
): Promise<Pick<MetadataListResponse, 'data' | 'total'>> {
|
||||
const endpointPolicies = await this.getAllEndpointPackagePolicies();
|
||||
const endpointPolicyIds = uniq(endpointPolicies.flatMap((policy) => policy.policy_ids));
|
||||
const unitedIndexQuery = await buildUnitedIndexQuery(soClient, queryOptions, endpointPolicyIds);
|
||||
const unitedIndexQuery = await buildUnitedIndexQuery(
|
||||
this.soClient,
|
||||
queryOptions,
|
||||
endpointPolicyIds
|
||||
);
|
||||
|
||||
let unitedMetadataQueryResponse: SearchResponse<UnitedAgentMetadataPersistedData>;
|
||||
|
||||
try {
|
||||
unitedMetadataQueryResponse = await esClient.search<UnitedAgentMetadataPersistedData>(
|
||||
unitedMetadataQueryResponse = await this.esClient.search<UnitedAgentMetadataPersistedData>(
|
||||
unitedIndexQuery
|
||||
);
|
||||
} catch (error) {
|
||||
|
@ -404,8 +353,8 @@ export class EndpointMetadataService {
|
|||
const agentPolicyIds: string[] = docs.map((doc) => doc._source?.united?.agent?.policy_id ?? '');
|
||||
|
||||
const agentPolicies =
|
||||
(await this.agentPolicyService
|
||||
.getByIds(this.DANGEROUS_INTERNAL_SO_CLIENT, agentPolicyIds)
|
||||
(await this.fleetServices.agentPolicy
|
||||
.getByIds(this.soClient, agentPolicyIds)
|
||||
.catch(catchAndWrapError)) ?? [];
|
||||
|
||||
const agentPoliciesMap = agentPolicies.reduce<Record<string, AgentPolicy>>(
|
||||
|
@ -450,9 +399,7 @@ export class EndpointMetadataService {
|
|||
...runtimeFields,
|
||||
};
|
||||
|
||||
hosts.push(
|
||||
await this.enrichHostMetadata(fleetServices, metadata, agent, agentPolicy, endpointPolicy)
|
||||
);
|
||||
hosts.push(await this.enrichHostMetadata(metadata, agent, agentPolicy, endpointPolicy));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,18 +410,12 @@ export class EndpointMetadataService {
|
|||
}
|
||||
|
||||
async getAllEndpointPackagePolicies() {
|
||||
return getAllEndpointPackagePolicies(
|
||||
this.packagePolicyService,
|
||||
this.DANGEROUS_INTERNAL_SO_CLIENT
|
||||
);
|
||||
return getAllEndpointPackagePolicies(this.fleetServices.packagePolicy, this.soClient);
|
||||
}
|
||||
|
||||
async getMetadataForEndpoints(
|
||||
esClient: ElasticsearchClient,
|
||||
endpointIDs: string[]
|
||||
): Promise<HostMetadata[]> {
|
||||
async getMetadataForEndpoints(endpointIDs: string[]): Promise<HostMetadata[]> {
|
||||
const query = getESQueryHostMetadataByIDs(endpointIDs);
|
||||
const { body } = await esClient.search<HostMetadata>(query, {
|
||||
const { body } = await this.esClient.search<HostMetadata>(query, {
|
||||
meta: true,
|
||||
});
|
||||
const hosts = queryResponseToHostListResult(body);
|
||||
|
|
|
@ -6,30 +6,14 @@
|
|||
*/
|
||||
|
||||
import type { SavedObjectsServiceStart } from '@kbn/core/server';
|
||||
import { loggingSystemMock, savedObjectsServiceMock } from '@kbn/core/server/mocks';
|
||||
import {
|
||||
createMockAgentPolicyService,
|
||||
createMockAgentService,
|
||||
createMockPackageService,
|
||||
createPackagePolicyServiceMock,
|
||||
} from '@kbn/fleet-plugin/server/mocks';
|
||||
import { coreMock, type ElasticsearchClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
||||
import type { createPackagePolicyServiceMock } from '@kbn/fleet-plugin/server/mocks';
|
||||
import type { AgentPolicyServiceInterface, AgentService } from '@kbn/fleet-plugin/server';
|
||||
import { createEndpointFleetServicesFactoryMock } from '../fleet/endpoint_fleet_services_factory.mocks';
|
||||
import { createMockEndpointAppContextServiceStartContract } from '../../mocks';
|
||||
import { EndpointMetadataService } from './endpoint_metadata_service';
|
||||
import type { EndpointInternalFleetServicesInterface } from '../fleet/endpoint_fleet_services_factory';
|
||||
import { EndpointFleetServicesFactory } from '../fleet/endpoint_fleet_services_factory';
|
||||
|
||||
const createCustomizedPackagePolicyService = () => {
|
||||
const service = createPackagePolicyServiceMock();
|
||||
service.list.mockImplementation(async (_, options) => {
|
||||
return {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: options.page ?? 1,
|
||||
perPage: options.perPage ?? 10,
|
||||
};
|
||||
});
|
||||
return service;
|
||||
};
|
||||
import { SavedObjectsClientFactory } from '../saved_objects';
|
||||
|
||||
/**
|
||||
* Endpoint Metadata Service test context. Includes an instance of `EndpointMetadataService` along with the
|
||||
|
@ -43,44 +27,49 @@ export interface EndpointMetadataServiceTestContextMock {
|
|||
endpointMetadataService: EndpointMetadataService;
|
||||
fleetServices: EndpointInternalFleetServicesInterface;
|
||||
logger: ReturnType<ReturnType<typeof loggingSystemMock.create>['get']>;
|
||||
esClient: ElasticsearchClientMock;
|
||||
}
|
||||
|
||||
export const createEndpointMetadataServiceTestContextMock = (
|
||||
savedObjectsStart: jest.Mocked<SavedObjectsServiceStart> = savedObjectsServiceMock.createStartContract(),
|
||||
agentService: jest.Mocked<AgentService> = createMockAgentService(),
|
||||
agentPolicyService: jest.Mocked<AgentPolicyServiceInterface> = createMockAgentPolicyService(),
|
||||
packagePolicyService: ReturnType<
|
||||
typeof createPackagePolicyServiceMock
|
||||
> = createCustomizedPackagePolicyService(),
|
||||
packageService: ReturnType<typeof createMockPackageService> = createMockPackageService(),
|
||||
logger: ReturnType<ReturnType<typeof loggingSystemMock.create>['get']> = loggingSystemMock
|
||||
.create()
|
||||
.get()
|
||||
): EndpointMetadataServiceTestContextMock => {
|
||||
const fleetServices = new EndpointFleetServicesFactory(
|
||||
{
|
||||
agentService,
|
||||
packageService,
|
||||
packagePolicyService,
|
||||
agentPolicyService,
|
||||
},
|
||||
savedObjectsStart
|
||||
).asInternalUser();
|
||||
export const createEndpointMetadataServiceTestContextMock =
|
||||
(): EndpointMetadataServiceTestContextMock => {
|
||||
const logger = loggingSystemMock.create().get();
|
||||
const { esClient, fleetStartServices, savedObjectsServiceStart } =
|
||||
createMockEndpointAppContextServiceStartContract();
|
||||
const savedObjectsServiceFactory = new SavedObjectsClientFactory(
|
||||
savedObjectsServiceStart,
|
||||
coreMock.createSetup().http
|
||||
);
|
||||
const fleetServices = createEndpointFleetServicesFactoryMock({
|
||||
fleetDependencies: fleetStartServices,
|
||||
savedObjects: savedObjectsServiceFactory,
|
||||
}).service.asInternalUser();
|
||||
const endpointMetadataService = new EndpointMetadataService(
|
||||
esClient,
|
||||
savedObjectsServiceFactory.createInternalScopedSoClient({ readonly: false }),
|
||||
fleetServices,
|
||||
logger
|
||||
);
|
||||
|
||||
const endpointMetadataService = new EndpointMetadataService(
|
||||
savedObjectsStart,
|
||||
agentPolicyService,
|
||||
packagePolicyService,
|
||||
logger
|
||||
);
|
||||
fleetServices.packagePolicy.list.mockImplementation(async (_, options) => {
|
||||
return {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: options.page ?? 1,
|
||||
perPage: options.perPage ?? 10,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
savedObjectsStart,
|
||||
agentService,
|
||||
agentPolicyService,
|
||||
packagePolicyService,
|
||||
endpointMetadataService,
|
||||
fleetServices,
|
||||
logger,
|
||||
return {
|
||||
savedObjectsStart: savedObjectsServiceStart,
|
||||
agentService: {
|
||||
asInternalUser: fleetServices.agent,
|
||||
asScoped: jest.fn().mockReturnValue(fleetServices.agent),
|
||||
},
|
||||
agentPolicyService: fleetServices.agentPolicy,
|
||||
packagePolicyService: fleetServices.packagePolicy,
|
||||
logger,
|
||||
endpointMetadataService,
|
||||
fleetServices,
|
||||
esClient: esClient as ElasticsearchClientMock,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './saved_objects_client_factory';
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 type { SavedObjectsServiceStart } from '@kbn/core-saved-objects-server';
|
||||
import type { HttpServiceSetup } from '@kbn/core/server';
|
||||
import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks';
|
||||
import { coreMock } from '@kbn/core/server/mocks';
|
||||
import { SavedObjectsClientFactory } from './saved_objects_client_factory';
|
||||
|
||||
interface CreateSavedObjectsClientFactoryMockOptions {
|
||||
savedObjectsServiceStart: jest.Mocked<SavedObjectsServiceStart>;
|
||||
httpServiceSetup: HttpServiceSetup;
|
||||
}
|
||||
|
||||
export const createSavedObjectsClientFactoryMock = (
|
||||
dependencies: Partial<CreateSavedObjectsClientFactoryMockOptions> = {}
|
||||
): {
|
||||
service: SavedObjectsClientFactory;
|
||||
dependencies: CreateSavedObjectsClientFactoryMockOptions;
|
||||
} => {
|
||||
const {
|
||||
savedObjectsServiceStart = savedObjectsServiceMock.createStartContract(),
|
||||
httpServiceSetup = coreMock.createSetup().http,
|
||||
} = dependencies;
|
||||
const service = new SavedObjectsClientFactory(savedObjectsServiceStart, httpServiceSetup);
|
||||
const soClient = service.createInternalUnscopedSoClient(false);
|
||||
const createInternalScopedSoClientSpy = jest.spyOn(service, 'createInternalScopedSoClient');
|
||||
const createInternalUnscopedSoClientSpy = jest.spyOn(service, 'createInternalUnscopedSoClient');
|
||||
|
||||
createInternalScopedSoClientSpy.mockReturnValue(soClient);
|
||||
createInternalUnscopedSoClientSpy.mockReturnValue(soClient);
|
||||
|
||||
return {
|
||||
service,
|
||||
dependencies: { savedObjectsServiceStart, httpServiceSetup },
|
||||
};
|
||||
};
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,max-classes-per-file */
|
||||
|
||||
import type { SavedObjectsServiceStart } from '@kbn/core-saved-objects-server';
|
||||
import { SECURITY_EXTENSION_ID, SPACES_EXTENSION_ID } from '@kbn/core-saved-objects-server';
|
||||
import type { HttpServiceSetup } from '@kbn/core/server';
|
||||
import { type SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { CoreKibanaRequest } from '@kbn/core-http-router-server-internal';
|
||||
import { DEFAULT_SPACE_ID, addSpaceIdToPath } from '@kbn/spaces-plugin/common';
|
||||
import { EndpointError } from '../../../../common/endpoint/errors';
|
||||
|
||||
type SavedObjectsClientContractKeys = keyof SavedObjectsClientContract;
|
||||
|
||||
const RESTRICTED_METHODS: readonly SavedObjectsClientContractKeys[] = [
|
||||
'bulkCreate',
|
||||
'bulkUpdate',
|
||||
'create',
|
||||
'createPointInTimeFinder',
|
||||
'delete',
|
||||
'removeReferencesTo',
|
||||
'update',
|
||||
'updateObjectsSpaces',
|
||||
];
|
||||
|
||||
export class InternalReadonlySoClientMethodNotAllowedError extends EndpointError {}
|
||||
|
||||
/**
|
||||
* Factory service for accessing saved object clients
|
||||
*/
|
||||
export class SavedObjectsClientFactory {
|
||||
constructor(
|
||||
private readonly savedObjectsServiceStart: SavedObjectsServiceStart,
|
||||
private readonly httpServiceSetup: HttpServiceSetup
|
||||
) {}
|
||||
|
||||
protected createFakeHttpRequest(spaceId: string = DEFAULT_SPACE_ID): CoreKibanaRequest {
|
||||
const fakeRequest = CoreKibanaRequest.from({
|
||||
headers: {},
|
||||
path: '/',
|
||||
route: { settings: {} },
|
||||
url: { href: {}, hash: '' } as URL,
|
||||
raw: { req: { url: '/' } } as any,
|
||||
});
|
||||
|
||||
if (spaceId && spaceId !== DEFAULT_SPACE_ID) {
|
||||
this.httpServiceSetup.basePath.set(fakeRequest, addSpaceIdToPath('/', spaceId));
|
||||
}
|
||||
|
||||
return fakeRequest;
|
||||
}
|
||||
|
||||
protected toReadonly(soClient: SavedObjectsClientContract): SavedObjectsClientContract {
|
||||
return new Proxy(soClient, {
|
||||
get(
|
||||
target: SavedObjectsClientContract,
|
||||
methodName: SavedObjectsClientContractKeys,
|
||||
receiver: unknown
|
||||
): unknown {
|
||||
if (RESTRICTED_METHODS.includes(methodName)) {
|
||||
throw new InternalReadonlySoClientMethodNotAllowedError(
|
||||
`Method [${methodName}] not allowed on internal readonly SO Client`
|
||||
);
|
||||
}
|
||||
|
||||
return Reflect.get(target, methodName, receiver);
|
||||
},
|
||||
}) as SavedObjectsClientContract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SavedObjects client that is scoped to a space (default: `Default`)
|
||||
*/
|
||||
createInternalScopedSoClient({
|
||||
spaceId = DEFAULT_SPACE_ID,
|
||||
readonly = true,
|
||||
}: Partial<{ spaceId: string; readonly: boolean }> = {}): SavedObjectsClientContract {
|
||||
const soClient = this.savedObjectsServiceStart.getScopedClient(
|
||||
this.createFakeHttpRequest(spaceId),
|
||||
{ excludedExtensions: [SECURITY_EXTENSION_ID] }
|
||||
);
|
||||
|
||||
if (readonly) {
|
||||
return this.toReadonly(soClient);
|
||||
}
|
||||
|
||||
return soClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SavedObjects client that is un-scoped to a space and thus can access all
|
||||
* data across all spaces.
|
||||
*
|
||||
* **WARNING:** Use with care!
|
||||
*/
|
||||
createInternalUnscopedSoClient(readonly: boolean = true): SavedObjectsClientContract {
|
||||
const soClient = this.savedObjectsServiceStart.getScopedClient(this.createFakeHttpRequest(), {
|
||||
excludedExtensions: [SECURITY_EXTENSION_ID, SPACES_EXTENSION_ID],
|
||||
});
|
||||
|
||||
if (readonly) {
|
||||
return this.toReadonly(soClient);
|
||||
}
|
||||
|
||||
return soClient;
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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 { savedObjectsServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import type { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import {
|
||||
createInternalReadonlySoClient,
|
||||
InternalReadonlySoClientMethodNotAllowedError,
|
||||
} from './create_internal_readonly_so_client';
|
||||
|
||||
describe('When using the `createInternalReadonlySoClient`', () => {
|
||||
let realSoClientMock: ReturnType<typeof savedObjectsClientMock.create>;
|
||||
let readonlySoClient: ReturnType<typeof createInternalReadonlySoClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
const soStartContract = savedObjectsServiceMock.createStartContract();
|
||||
realSoClientMock = savedObjectsClientMock.create();
|
||||
soStartContract.getScopedClient.mockReturnValue(realSoClientMock);
|
||||
readonlySoClient = createInternalReadonlySoClient(soStartContract);
|
||||
});
|
||||
|
||||
it.each<keyof SavedObjectsClientContract>([
|
||||
'get',
|
||||
'bulkGet',
|
||||
'checkConflicts',
|
||||
'collectMultiNamespaceReferences',
|
||||
'find',
|
||||
'resolve',
|
||||
])('should allow usage of %s() method', (methodName) => {
|
||||
expect(() => readonlySoClient[methodName]).not.toThrow();
|
||||
});
|
||||
|
||||
it.each<keyof SavedObjectsClientContract>([
|
||||
'bulkCreate',
|
||||
'bulkUpdate',
|
||||
'create',
|
||||
'createPointInTimeFinder',
|
||||
'delete',
|
||||
'removeReferencesTo',
|
||||
'openPointInTimeForType',
|
||||
'closePointInTime',
|
||||
'update',
|
||||
'updateObjectsSpaces',
|
||||
])('should throw if usage of %s() is attempted', (methodName) => {
|
||||
expect(() => readonlySoClient[methodName]).toThrow(
|
||||
InternalReadonlySoClientMethodNotAllowedError
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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 type { SavedObjectsClientContract, SavedObjectsServiceStart } from '@kbn/core/server';
|
||||
import { createInternalSoClient } from './create_internal_so_client';
|
||||
import { EndpointError } from '../../../common/endpoint/errors';
|
||||
|
||||
type SavedObjectsClientContractKeys = keyof SavedObjectsClientContract;
|
||||
|
||||
const RESTRICTED_METHODS: readonly SavedObjectsClientContractKeys[] = [
|
||||
'bulkCreate',
|
||||
'bulkUpdate',
|
||||
'create',
|
||||
'createPointInTimeFinder',
|
||||
'delete',
|
||||
'removeReferencesTo',
|
||||
'openPointInTimeForType',
|
||||
'closePointInTime',
|
||||
'update',
|
||||
'updateObjectsSpaces',
|
||||
];
|
||||
|
||||
export class InternalReadonlySoClientMethodNotAllowedError extends EndpointError {}
|
||||
|
||||
/**
|
||||
* Creates an internal (system user) Saved Objects client (permissions turned off) that can only perform READ
|
||||
* operations.
|
||||
*/
|
||||
export const createInternalReadonlySoClient = (
|
||||
savedObjectsServiceStart: SavedObjectsServiceStart
|
||||
): SavedObjectsClientContract => {
|
||||
const internalSoClient = createInternalSoClient(savedObjectsServiceStart);
|
||||
|
||||
return new Proxy(internalSoClient, {
|
||||
get(
|
||||
target: SavedObjectsClientContract,
|
||||
methodName: SavedObjectsClientContractKeys,
|
||||
receiver: unknown
|
||||
): unknown {
|
||||
if (RESTRICTED_METHODS.includes(methodName)) {
|
||||
throw new InternalReadonlySoClientMethodNotAllowedError(
|
||||
`Method [${methodName}] not allowed on internal readonly SO Client`
|
||||
);
|
||||
}
|
||||
|
||||
return Reflect.get(target, methodName, receiver);
|
||||
},
|
||||
}) as SavedObjectsClientContract;
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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 type { SavedObjectsServiceStart } from '@kbn/core-saved-objects-server';
|
||||
import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server';
|
||||
import type { KibanaRequest, SavedObjectsClientContract } from '@kbn/core/server';
|
||||
|
||||
export const createInternalSoClient = (
|
||||
savedObjectsServiceStart: SavedObjectsServiceStart
|
||||
): SavedObjectsClientContract => {
|
||||
const fakeRequest = {
|
||||
headers: {},
|
||||
getBasePath: () => '',
|
||||
path: '/',
|
||||
route: { settings: {} },
|
||||
url: { href: {} },
|
||||
raw: { req: { url: '/' } },
|
||||
} as unknown as KibanaRequest;
|
||||
|
||||
return savedObjectsServiceStart.getScopedClient(fakeRequest, {
|
||||
excludedExtensions: [SECURITY_EXTENSION_ID],
|
||||
});
|
||||
};
|
|
@ -10,7 +10,6 @@ import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types
|
|||
import {
|
||||
elasticsearchServiceMock,
|
||||
httpServerMock,
|
||||
loggingSystemMock,
|
||||
savedObjectsClientMock,
|
||||
} from '@kbn/core/server/mocks';
|
||||
import {
|
||||
|
@ -76,13 +75,15 @@ import type {
|
|||
PostAgentPolicyCreateCallback,
|
||||
PutPackagePolicyUpdateCallback,
|
||||
} from '@kbn/fleet-plugin/server/types';
|
||||
import type { EndpointMetadataService } from '../endpoint/services/metadata';
|
||||
import { createEndpointMetadataServiceTestContextMock } from '../endpoint/services/metadata/mocks';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: (): string => 'NEW_UUID',
|
||||
}));
|
||||
|
||||
describe('ingest_integration tests ', () => {
|
||||
let endpointAppContextMock: EndpointAppContextServiceStartContract;
|
||||
let endpointAppContextStartContract: EndpointAppContextServiceStartContract;
|
||||
let req: KibanaRequest;
|
||||
let ctx: ReturnType<typeof requestContextMock.create>;
|
||||
const exceptionListClient: ExceptionListClient = getExceptionListClientMock();
|
||||
|
@ -100,18 +101,24 @@ describe('ingest_integration tests ', () => {
|
|||
const generator = new EndpointDocGenerator();
|
||||
const cloudService = cloudMock.createSetup();
|
||||
let productFeaturesService: ProductFeaturesService;
|
||||
let endpointMetadataService: EndpointMetadataService;
|
||||
let logger: Logger;
|
||||
|
||||
beforeEach(() => {
|
||||
endpointAppContextMock = createMockEndpointAppContextServiceStartContract();
|
||||
endpointAppContextStartContract = createMockEndpointAppContextServiceStartContract();
|
||||
ctx = requestContextMock.createTools().context;
|
||||
req = httpServerMock.createKibanaRequest();
|
||||
licenseEmitter = new Subject();
|
||||
licenseService = new LicenseService();
|
||||
licenseService.start(licenseEmitter);
|
||||
productFeaturesService = endpointAppContextMock.productFeaturesService;
|
||||
productFeaturesService = endpointAppContextStartContract.productFeaturesService;
|
||||
|
||||
const metadataMocks = createEndpointMetadataServiceTestContextMock();
|
||||
logger = metadataMocks.logger;
|
||||
endpointMetadataService = metadataMocks.endpointMetadataService;
|
||||
|
||||
jest
|
||||
.spyOn(endpointAppContextMock.endpointMetadataService, 'getFleetEndpointPackagePolicy')
|
||||
.spyOn(endpointMetadataService, 'getFleetEndpointPackagePolicy')
|
||||
.mockResolvedValue(createMockPolicyData());
|
||||
});
|
||||
|
||||
|
@ -156,12 +163,11 @@ describe('ingest_integration tests ', () => {
|
|||
});
|
||||
|
||||
const invokeCallback = async (manifestManager: ManifestManager): Promise<NewPackagePolicy> => {
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyCreateCallback(
|
||||
logger,
|
||||
manifestManager,
|
||||
requestContextFactoryMock.create(),
|
||||
endpointAppContextMock.alerting,
|
||||
endpointAppContextStartContract.alerting,
|
||||
licenseService,
|
||||
exceptionListClient,
|
||||
cloudService,
|
||||
|
@ -346,7 +352,6 @@ describe('ingest_integration tests ', () => {
|
|||
describe('package policy post create callback', () => {
|
||||
const soClient = savedObjectsClientMock.create();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyPostCreateCallback(logger, exceptionListClient);
|
||||
const policyConfig = generator.generatePolicyPackagePolicy() as PackagePolicy;
|
||||
|
||||
|
@ -420,8 +425,6 @@ describe('ingest_integration tests ', () => {
|
|||
|
||||
describe('agent policy update callback', () => {
|
||||
it('ProductFeature disabled - returns an error if higher tier features are turned on in the policy', async () => {
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
|
||||
productFeaturesService = createProductFeaturesServiceMock(
|
||||
ALL_PRODUCT_FEATURE_KEYS.filter(
|
||||
(key) => key !== ProductFeatureSecurityKey.endpointAgentTamperProtection
|
||||
|
@ -437,8 +440,6 @@ describe('ingest_integration tests ', () => {
|
|||
);
|
||||
});
|
||||
it('ProductFeature disabled - returns agent policy if higher tier features are turned off in the policy', async () => {
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
|
||||
productFeaturesService = createProductFeaturesServiceMock(
|
||||
ALL_PRODUCT_FEATURE_KEYS.filter(
|
||||
(key) => key !== ProductFeatureSecurityKey.endpointAgentTamperProtection
|
||||
|
@ -453,8 +454,6 @@ describe('ingest_integration tests ', () => {
|
|||
expect(updatedPolicyConfig).toEqual(policyConfig);
|
||||
});
|
||||
it('ProductFeature enabled - returns agent policy if higher tier features are turned on in the policy', async () => {
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
|
||||
const callback = getAgentPolicyUpdateCallback(logger, productFeaturesService);
|
||||
|
||||
const policyConfig = generator.generateAgentPolicy();
|
||||
|
@ -465,8 +464,6 @@ describe('ingest_integration tests ', () => {
|
|||
expect(updatedPolicyConfig).toEqual(policyConfig);
|
||||
});
|
||||
it('ProductFeature enabled - returns agent policy if higher tier features are turned off in the policy', async () => {
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
|
||||
const callback = getAgentPolicyUpdateCallback(logger, productFeaturesService);
|
||||
const policyConfig = generator.generateAgentPolicy();
|
||||
|
||||
|
@ -477,12 +474,10 @@ describe('ingest_integration tests ', () => {
|
|||
});
|
||||
|
||||
describe('agent policy create callback', () => {
|
||||
let logger: Logger;
|
||||
let callback: PostAgentPolicyCreateCallback;
|
||||
let policyConfig: GetAgentPoliciesResponseItem;
|
||||
|
||||
beforeEach(() => {
|
||||
logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
callback = getAgentPolicyCreateCallback(logger, productFeaturesService);
|
||||
policyConfig = generator.generateAgentPolicy();
|
||||
});
|
||||
|
@ -537,12 +532,11 @@ describe('ingest_integration tests ', () => {
|
|||
});
|
||||
it('returns an error if paid features are turned on in the policy', async () => {
|
||||
const mockPolicy = policyFactory(); // defaults with paid features on
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -558,12 +552,11 @@ describe('ingest_integration tests ', () => {
|
|||
it('updates successfully if no paid features are turned on in the policy', async () => {
|
||||
const mockPolicy = policyFactoryWithoutPaidFeatures();
|
||||
mockPolicy.windows.malware.mode = ProtectionModes.detect;
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -594,10 +587,10 @@ describe('ingest_integration tests ', () => {
|
|||
ALL_PRODUCT_FEATURE_KEYS.filter((key) => key !== 'endpoint_protection_updates')
|
||||
);
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
endpointAppContextMock.logger,
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -649,12 +642,11 @@ describe('ingest_integration tests ', () => {
|
|||
'should return bad request for invalid endpoint package policy global manifest values',
|
||||
async ({ date, message }) => {
|
||||
const mockPolicy = policyFactory(); // defaults with paid features on
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -715,12 +707,11 @@ describe('ingest_integration tests ', () => {
|
|||
'should return bad request for invalid endpoint package policy global manifest values',
|
||||
async ({ date, message }) => {
|
||||
const mockPolicy = policyFactory(); // defaults with paid features on
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -759,12 +750,11 @@ describe('ingest_integration tests ', () => {
|
|||
it('updates successfully when paid features are turned on', async () => {
|
||||
const mockPolicy = policyFactory();
|
||||
mockPolicy.windows.popup.malware.message = 'paid feature';
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -786,10 +776,10 @@ describe('ingest_integration tests ', () => {
|
|||
ALL_PRODUCT_FEATURE_KEYS.filter((key) => key !== 'endpoint_policy_protections')
|
||||
);
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
endpointAppContextMock.logger,
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -864,12 +854,11 @@ describe('ingest_integration tests ', () => {
|
|||
mockPolicy.meta.license_uuid = 'updated-uid';
|
||||
mockPolicy.meta.serverless = false;
|
||||
mockPolicy.meta.billable = false;
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -903,12 +892,11 @@ describe('ingest_integration tests ', () => {
|
|||
mockPolicy.meta.license_uuid = 'updated-uid';
|
||||
mockPolicy.meta.serverless = false;
|
||||
mockPolicy.meta.billable = false;
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -936,7 +924,6 @@ describe('ingest_integration tests ', () => {
|
|||
describe('when `antivirus_registration.mode` is changed', () => {
|
||||
const soClient = savedObjectsClientMock.create();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
let callback: PutPackagePolicyUpdateCallback;
|
||||
let inputPolicyConfig: PolicyData;
|
||||
let inputWindowsConfig: PolicyConfig['windows'];
|
||||
|
@ -950,8 +937,8 @@ describe('ingest_integration tests ', () => {
|
|||
callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
@ -1044,14 +1031,13 @@ describe('ingest_integration tests ', () => {
|
|||
|
||||
const soClient = savedObjectsClientMock.create();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const logger = loggingSystemMock.create().get('ingest_integration.test');
|
||||
licenseEmitter.next(Enterprise);
|
||||
|
||||
const callback = getPackagePolicyUpdateCallback(
|
||||
logger,
|
||||
licenseService,
|
||||
endpointAppContextMock.featureUsageService,
|
||||
endpointAppContextMock.endpointMetadataService,
|
||||
endpointAppContextStartContract.featureUsageService,
|
||||
endpointMetadataService,
|
||||
cloudService,
|
||||
esClient,
|
||||
productFeaturesService
|
||||
|
|
|
@ -41,7 +41,7 @@ export const getAllIntegrationsRoute = (router: SecuritySolutionPluginRouter) =>
|
|||
|
||||
const [packages, packagePolicies] = await Promise.all([
|
||||
fleet.packages.getPackages(),
|
||||
fleet.packagePolicy.list(fleet.internalReadonlySoClient, {}),
|
||||
fleet.packagePolicy.list(fleet.savedObjects.createInternalScopedSoClient(), {}),
|
||||
]);
|
||||
// Elastic prebuilt rules is a special package and should be skipped
|
||||
const packagesWithoutPrebuiltSecurityRules = packages.filter(
|
||||
|
|
|
@ -46,7 +46,7 @@ export const getInstalledIntegrationsRoute = (router: SecuritySolutionPluginRout
|
|||
});
|
||||
|
||||
const packagePolicies = await fleet.packagePolicy.list(
|
||||
fleet.internalReadonlySoClient,
|
||||
fleet.savedObjects.createInternalScopedSoClient(),
|
||||
{}
|
||||
);
|
||||
packagePolicies.items.forEach((policy) => {
|
||||
|
|
|
@ -37,8 +37,8 @@ describe('When using Artifacts Exceptions BaseValidator', () => {
|
|||
|
||||
const servicesStart = createMockEndpointAppContextServiceStartContract();
|
||||
|
||||
packagePolicyService = servicesStart.endpointFleetServicesFactory.asInternalUser()
|
||||
.packagePolicy as jest.Mocked<PackagePolicyClient>;
|
||||
packagePolicyService = servicesStart.fleetStartServices
|
||||
.packagePolicyService as jest.Mocked<PackagePolicyClient>;
|
||||
|
||||
endpointAppContextServices = new EndpointAppContextService();
|
||||
endpointAppContextServices.setup(createMockEndpointAppContextServiceSetupContract());
|
||||
|
@ -48,7 +48,9 @@ describe('When using Artifacts Exceptions BaseValidator', () => {
|
|||
if (withNoAuth) {
|
||||
const fleetAuthz = createFleetAuthzMock();
|
||||
fleetAuthz.fleet.all = false;
|
||||
(servicesStart.fleetAuthzService?.fromRequest as jest.Mock).mockResolvedValue(fleetAuthz);
|
||||
(servicesStart.fleetStartServices.authz.fromRequest as jest.Mock).mockResolvedValue(
|
||||
fleetAuthz
|
||||
);
|
||||
(servicesStart.security.authc.getCurrentUser as jest.Mock).mockReturnValue(
|
||||
securityMock.createMockAuthenticatedUser()
|
||||
);
|
||||
|
|
|
@ -140,15 +140,15 @@ export class BaseValidator {
|
|||
*/
|
||||
protected async validateByPolicyItem(item: ExceptionItemLikeOptions): Promise<void> {
|
||||
if (this.isItemByPolicy(item)) {
|
||||
const { packagePolicy, internalReadonlySoClient } =
|
||||
this.endpointAppContext.getInternalFleetServices();
|
||||
const { packagePolicy, savedObjects } = this.endpointAppContext.getInternalFleetServices();
|
||||
const policyIds = getPolicyIdsFromArtifact(item);
|
||||
const soClient = savedObjects.createInternalScopedSoClient();
|
||||
|
||||
if (policyIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const policiesFromFleet = await packagePolicy.getByIDs(internalReadonlySoClient, policyIds, {
|
||||
const policiesFromFleet = await packagePolicy.getByIDs(soClient, policyIds, {
|
||||
ignoreMissing: true,
|
||||
});
|
||||
|
||||
|
|
|
@ -76,7 +76,6 @@ import { PolicyWatcher } from './endpoint/lib/policy/license_watch';
|
|||
import previewPolicy from './lib/detection_engine/routes/index/preview_policy.json';
|
||||
import type { IRuleMonitoringService } from './lib/detection_engine/rule_monitoring';
|
||||
import { createRuleMonitoringService } from './lib/detection_engine/rule_monitoring';
|
||||
import { EndpointMetadataService } from './endpoint/services/metadata';
|
||||
import type {
|
||||
CreateRuleAdditionalOptions,
|
||||
CreateRuleOptions,
|
||||
|
@ -103,7 +102,6 @@ import type {
|
|||
SecuritySolutionPluginStart,
|
||||
SecuritySolutionPluginStartDependencies,
|
||||
} from './plugin_contract';
|
||||
import { EndpointFleetServicesFactory } from './endpoint/services/fleet';
|
||||
import { featureUsageService } from './endpoint/services/feature_usage';
|
||||
import { setIsElasticCloudDeployment } from './lib/telemetry/helpers';
|
||||
import { artifactService } from './lib/telemetry/artifact';
|
||||
|
@ -239,6 +237,7 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
cloud: plugins.cloud,
|
||||
loggerFactory: this.pluginContext.logger,
|
||||
telemetry: core.analytics,
|
||||
httpServiceSetup: core.http,
|
||||
});
|
||||
|
||||
initUsageCollectors({
|
||||
|
@ -526,27 +525,10 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
// from where authz can be derived)
|
||||
false
|
||||
);
|
||||
const {
|
||||
authz,
|
||||
agentService,
|
||||
packageService,
|
||||
packagePolicyService,
|
||||
agentPolicyService,
|
||||
createFilesClient,
|
||||
createFleetActionsClient,
|
||||
} =
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
plugins.fleet!;
|
||||
let manifestManager: ManifestManager | undefined;
|
||||
const endpointFleetServicesFactory = new EndpointFleetServicesFactory(
|
||||
{
|
||||
agentService,
|
||||
packageService,
|
||||
packagePolicyService,
|
||||
agentPolicyService,
|
||||
},
|
||||
core.savedObjects
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const fleetStartServices = plugins.fleet!;
|
||||
|
||||
const { packageService } = fleetStartServices;
|
||||
|
||||
this.licensing$ = plugins.licensing.license$;
|
||||
|
||||
|
@ -563,26 +545,42 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
plugins.elasticAssistant.registerFeatures(APP_UI_ID, features);
|
||||
plugins.elasticAssistant.registerFeatures('management', features);
|
||||
|
||||
const manifestManager = new ManifestManager({
|
||||
savedObjectsClient,
|
||||
exceptionListClient,
|
||||
artifactClient: new EndpointArtifactClient(
|
||||
fleetStartServices.createArtifactsClient('endpoint')
|
||||
),
|
||||
packagePolicyService: fleetStartServices.packagePolicyService,
|
||||
logger: this.pluginContext.logger.get('ManifestManager'),
|
||||
experimentalFeatures: config.experimentalFeatures,
|
||||
packagerTaskPackagePolicyUpdateBatchSize: config.packagerTaskPackagePolicyUpdateBatchSize,
|
||||
esClient: core.elasticsearch.client.asInternalUser,
|
||||
productFeaturesService,
|
||||
});
|
||||
|
||||
this.endpointAppContextService.start({
|
||||
fleetStartServices,
|
||||
security: core.security,
|
||||
alerting: plugins.alerting,
|
||||
config,
|
||||
cases: plugins.cases,
|
||||
manifestManager,
|
||||
licenseService,
|
||||
exceptionListsClient: exceptionListClient,
|
||||
registerListsServerExtension: this.lists?.registerExtension,
|
||||
featureUsageService,
|
||||
experimentalFeatures: config.experimentalFeatures,
|
||||
esClient: core.elasticsearch.client.asInternalUser,
|
||||
productFeaturesService,
|
||||
savedObjectsServiceStart: core.savedObjects,
|
||||
connectorActions: plugins.actions,
|
||||
});
|
||||
|
||||
if (this.lists && plugins.taskManager && plugins.fleet) {
|
||||
// Exceptions, Artifacts and Manifests start
|
||||
const taskManager = plugins.taskManager;
|
||||
const artifactClient = new EndpointArtifactClient(
|
||||
plugins.fleet.createArtifactsClient('endpoint')
|
||||
);
|
||||
|
||||
manifestManager = new ManifestManager({
|
||||
savedObjectsClient,
|
||||
artifactClient,
|
||||
exceptionListClient,
|
||||
packagePolicyService: plugins.fleet.packagePolicyService,
|
||||
logger: this.pluginContext.logger.get('ManifestManager'),
|
||||
experimentalFeatures: config.experimentalFeatures,
|
||||
packagerTaskPackagePolicyUpdateBatchSize: config.packagerTaskPackagePolicyUpdateBatchSize,
|
||||
esClient: core.elasticsearch.client.asInternalUser,
|
||||
productFeaturesService,
|
||||
});
|
||||
|
||||
// Migrate artifacts to fleet and then start the manifest task after that is done
|
||||
plugins.fleet
|
||||
.fleetSetupCompleted()
|
||||
.then(async () => {
|
||||
|
@ -595,24 +593,24 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
logger.error(new Error('User artifacts task not available.'));
|
||||
}
|
||||
|
||||
const fleetServices = this.endpointAppContextService.getInternalFleetServices();
|
||||
|
||||
await turnOffPolicyProtectionsIfNotSupported(
|
||||
core.elasticsearch.client.asInternalUser,
|
||||
endpointFleetServicesFactory.asInternalUser(),
|
||||
fleetServices,
|
||||
productFeaturesService,
|
||||
logger
|
||||
);
|
||||
|
||||
await turnOffAgentPolicyFeatures(
|
||||
endpointFleetServicesFactory.asInternalUser(),
|
||||
productFeaturesService,
|
||||
logger
|
||||
);
|
||||
await turnOffAgentPolicyFeatures(fleetServices, productFeaturesService, logger);
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
// License related start
|
||||
licenseService.start(this.licensing$);
|
||||
|
||||
featureUsageService.start(plugins.licensing);
|
||||
|
||||
this.policyWatcher = new PolicyWatcher(
|
||||
plugins.fleet.packagePolicyService,
|
||||
core.savedObjects,
|
||||
|
@ -622,36 +620,6 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
this.policyWatcher.start(licenseService);
|
||||
}
|
||||
|
||||
this.endpointAppContextService.start({
|
||||
fleetAuthzService: authz,
|
||||
createFleetFilesClient: createFilesClient,
|
||||
endpointMetadataService: new EndpointMetadataService(
|
||||
core.savedObjects,
|
||||
agentPolicyService,
|
||||
packagePolicyService,
|
||||
logger
|
||||
),
|
||||
endpointFleetServicesFactory,
|
||||
security: core.security,
|
||||
alerting: plugins.alerting,
|
||||
config,
|
||||
cases: plugins.cases,
|
||||
logger,
|
||||
manifestManager,
|
||||
registerIngestCallback,
|
||||
licenseService,
|
||||
exceptionListsClient: exceptionListClient,
|
||||
registerListsServerExtension: this.lists?.registerExtension,
|
||||
featureUsageService,
|
||||
experimentalFeatures: config.experimentalFeatures,
|
||||
messageSigningService: plugins.fleet?.messageSigningService,
|
||||
createFleetActionsClient,
|
||||
esClient: core.elasticsearch.client.asInternalUser,
|
||||
productFeaturesService,
|
||||
savedObjectsClient,
|
||||
connectorActions: plugins.actions,
|
||||
});
|
||||
|
||||
if (plugins.taskManager) {
|
||||
this.completeExternalResponseActionsTask
|
||||
.start({
|
||||
|
|
|
@ -170,14 +170,13 @@ export const getHostEndpoint = async (
|
|||
const logger = endpointContext.logFactory.get('metadata');
|
||||
|
||||
try {
|
||||
const fleetServices = endpointContext.service.getInternalFleetServices();
|
||||
const endpointMetadataService = endpointContext.service.getEndpointMetadataService();
|
||||
|
||||
const endpointData = await endpointMetadataService
|
||||
// Using `internalUser` ES client below due to the fact that Fleet data has been moved to
|
||||
// system indices (`.fleet*`). Because this is a readonly action, this should be ok to do
|
||||
// here until proper RBOC controls are implemented
|
||||
.getEnrichedHostMetadata(esClient.asInternalUser, fleetServices, id);
|
||||
.getEnrichedHostMetadata(id);
|
||||
|
||||
const fleetAgentId = endpointData.metadata.elastic.agent.id;
|
||||
|
||||
|
|
|
@ -226,5 +226,8 @@
|
|||
"@kbn/inference-plugin",
|
||||
"@kbn/entityManager-plugin",
|
||||
"@kbn/entities-schema",
|
||||
"@kbn/inference-plugin",
|
||||
"@kbn/core-saved-objects-server-mocks",
|
||||
"@kbn/core-http-router-server-internal",
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue