Skip to content

Commit

Permalink
[Security Solution] endpoint metadata transform stats API (#120429)
Browse files Browse the repository at this point in the history
  • Loading branch information
joeypoon authored Dec 6, 2021
1 parent 1b976c9 commit 7fc30d5
Show file tree
Hide file tree
Showing 13 changed files with 244 additions and 154 deletions.
3 changes: 0 additions & 3 deletions x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import type { TransformConfigSchema } from './transforms/types';
import { ENABLE_CASE_CONNECTOR } from '../../cases/common';
import { METADATA_TRANSFORMS_PATTERN } from './endpoint/constants';

/**
* as const
Expand Down Expand Up @@ -362,8 +361,6 @@ export const showAllOthersBucket: string[] = [
*/
export const ELASTIC_NAME = 'estc' as const;

export const METADATA_TRANSFORM_STATS_URL = `/api/transform/transforms/${METADATA_TRANSFORMS_PATTERN}/_stats`;

export const RISKY_HOSTS_INDEX_PREFIX = 'ml_host_risk_score_latest_' as const;

export const TRANSFORM_STATES = {
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/security_solution/common/endpoint/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const LIMITED_CONCURRENCY_ENDPOINT_COUNT = 100;
export const BASE_ENDPOINT_ROUTE = '/api/endpoint';
export const HOST_METADATA_LIST_ROUTE = `${BASE_ENDPOINT_ROUTE}/metadata`;
export const HOST_METADATA_GET_ROUTE = `${BASE_ENDPOINT_ROUTE}/metadata/{id}`;
export const METADATA_TRANSFORMS_STATUS_ROUTE = `${BASE_ENDPOINT_ROUTE}/metadata/transforms`;

export const TRUSTED_APPS_GET_API = `${BASE_ENDPOINT_ROUTE}/trusted_apps/{id}`;
export const TRUSTED_APPS_LIST_API = `${BASE_ENDPOINT_ROUTE}/trusted_apps`;
Expand All @@ -68,3 +69,6 @@ export const failedFleetActionErrorCode = '424';

export const ENDPOINT_DEFAULT_PAGE = 0;
export const ENDPOINT_DEFAULT_PAGE_SIZE = 10;

export const FORBIDDEN_MESSAGE =
'You do not have permission to perform this action or license level does not allow for this action';
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ import {
ENDPOINT_ACTION_LOG_ROUTE,
HOST_METADATA_GET_ROUTE,
HOST_METADATA_LIST_ROUTE,
METADATA_TRANSFORMS_STATUS_ROUTE,
} from '../../../../common/endpoint/constants';
import {
pendingActionsHttpMock,
PendingActionsHttpMockInterface,
} from '../../../common/lib/endpoint_pending_actions/mocks';
import { METADATA_TRANSFORM_STATS_URL, TRANSFORM_STATES } from '../../../../common/constants';
import { TRANSFORM_STATES } from '../../../../common/constants';
import { TransformStatsResponse } from './types';
import {
fleetGetAgentPolicyListHttpMock,
Expand Down Expand Up @@ -162,7 +163,7 @@ export const failedTransformStateMock = {
export const transformsHttpMocks = httpHandlerMockFactory<TransformHttpMocksInterface>([
{
id: 'metadataTransformStats',
path: METADATA_TRANSFORM_STATS_URL,
path: METADATA_TRANSFORMS_STATUS_ROUTE,
method: 'get',
handler: () => failedTransformStateMock,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { CoreStart, HttpStart } from 'kibana/public';
import { Dispatch } from 'redux';
import semverGte from 'semver/functions/gte';
import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../fleet/common';
import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants';
import {
BASE_POLICY_RESPONSE_ROUTE,
ENDPOINT_ACTION_LOG_ROUTE,
HOST_METADATA_GET_ROUTE,
HOST_METADATA_LIST_ROUTE,
metadataCurrentIndexPattern,
METADATA_UNITED_INDEX,
METADATA_TRANSFORMS_STATUS_ROUTE,
} from '../../../../../common/endpoint/constants';
import {
ActivityLog,
Expand Down Expand Up @@ -783,7 +783,7 @@ export async function handleLoadMetadataTransformStats(http: HttpStart, store: E

try {
const transformStatsResponse: TransformStatsResponse = await http.get(
METADATA_TRANSFORM_STATS_URL
METADATA_TRANSFORMS_STATUS_ROUTE
);

dispatch({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import { pendingActionsResponseMock } from '../../../../common/lib/endpoint_pend
import {
ACTION_STATUS_ROUTE,
HOST_METADATA_LIST_ROUTE,
METADATA_TRANSFORMS_STATUS_ROUTE,
} from '../../../../../common/endpoint/constants';
import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants';
import { TransformStats, TransformStatsResponse } from '../types';

const generator = new EndpointDocGenerator('seed');
Expand Down Expand Up @@ -162,7 +162,7 @@ const endpointListApiPathHandlerMocks = ({
return pendingActionsResponseMock();
},

[METADATA_TRANSFORM_STATS_URL]: (): TransformStatsResponse => ({
[METADATA_TRANSFORMS_STATUS_ROUTE]: (): TransformStatsResponse => ({
count: transforms.length,
transforms,
}),
Expand Down
10 changes: 8 additions & 2 deletions x-pack/plugins/security_solution/server/endpoint/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import { createCasesClientMock } from '../../../cases/server/client/mocks';
import { requestContextFactoryMock } from '../request_context_factory.mock';
import { EndpointMetadataService } from './services/metadata';
import { createFleetAuthzMock } from '../../../fleet/common';
import { createMockClients } from '../lib/detection_engine/routes/__mocks__/request_context';
import type { EndpointAuthz } from '../../common/endpoint/types/authz';

/**
* Creates a mocked EndpointAppContext.
Expand Down Expand Up @@ -181,9 +183,13 @@ export const createMockMetadataRequestContext = (): jest.Mocked<MetadataRequestC

export function createRouteHandlerContext(
dataClient: jest.Mocked<IScopedClusterClient>,
savedObjectsClient: jest.Mocked<SavedObjectsClientContract>
savedObjectsClient: jest.Mocked<SavedObjectsClientContract>,
overrides: { endpointAuthz?: Partial<EndpointAuthz> } = {}
) {
const context = requestContextMock.create() as jest.Mocked<SecuritySolutionRequestHandlerContext>;
const context = requestContextMock.create(
createMockClients(),
overrides
) as jest.Mocked<SecuritySolutionRequestHandlerContext>;
context.core.elasticsearch.client = dataClient;
context.core.savedObjects.client = savedObjectsClient;
return context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
ISOLATE_HOST_ROUTE,
UNISOLATE_HOST_ROUTE,
failedFleetActionErrorCode,
FORBIDDEN_MESSAGE,
} from '../../../../common/endpoint/constants';
import { AGENT_ACTIONS_INDEX } from '../../../../../fleet/common';
import {
Expand Down Expand Up @@ -105,8 +106,7 @@ export const isolationRequestHandler = function (
if ((!canIsolateHost && isolate) || (!canUnIsolateHost && !isolate)) {
return res.forbidden({
body: {
message:
'You do not have permission to perform this action or license level does not allow for this action',
message: FORBIDDEN_MESSAGE,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import { GetMetadataListRequestQuery } from '../../../../common/endpoint/schema/
import {
ENDPOINT_DEFAULT_PAGE,
ENDPOINT_DEFAULT_PAGE_SIZE,
FORBIDDEN_MESSAGE,
METADATA_TRANSFORMS_PATTERN,
} from '../../../../common/endpoint/constants';
import { EndpointFleetServicesInterface } from '../../services/endpoint_fleet_services';

Expand Down Expand Up @@ -185,6 +187,34 @@ export const getMetadataRequestHandler = function (
};
};

export function getMetadataTransformStatsHandler(
logger: Logger
): RequestHandler<unknown, unknown, unknown, SecuritySolutionRequestHandlerContext> {
return async (context, _, response) => {
const { canAccessEndpointManagement } = context.securitySolution.endpointAuthz;
if (!canAccessEndpointManagement) {
return response.forbidden({
body: {
message: FORBIDDEN_MESSAGE,
},
});
}

const esClient = context.core.elasticsearch.client.asInternalUser;
try {
const transformStats = await esClient.transform.getTransformStats({
transform_id: METADATA_TRANSFORMS_PATTERN,
allow_no_match: true,
});
return response.ok({
body: transformStats.body,
});
} catch (error) {
return errorHandler(logger, response, error);
}
};
}

export async function mapToHostResultList(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryParams: Record<string, any>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ import { schema } from '@kbn/config-schema';

import { HostStatus } from '../../../../common/endpoint/types';
import { EndpointAppContext } from '../../types';
import { getLogger, getMetadataRequestHandler, getMetadataListRequestHandler } from './handlers';
import {
getLogger,
getMetadataRequestHandler,
getMetadataListRequestHandler,
getMetadataTransformStatsHandler,
} from './handlers';
import type { SecuritySolutionPluginRouter } from '../../../types';
import {
HOST_METADATA_GET_ROUTE,
HOST_METADATA_LIST_ROUTE,
METADATA_TRANSFORMS_STATUS_ROUTE,
} from '../../../../common/endpoint/constants';
import { GetMetadataListRequestSchema } from '../../../../common/endpoint/schema/metadata';

Expand Down Expand Up @@ -60,4 +66,13 @@ export function registerEndpointRoutes(
},
getMetadataRequestHandler(endpointAppContext, logger)
);

router.get(
{
path: METADATA_TRANSFORMS_STATUS_ROUTE,
validate: false,
options: { authRequired: true, tags: ['access:securitySolution'] },
},
getMetadataTransformStatsHandler(logger)
);
}
Loading

0 comments on commit 7fc30d5

Please sign in to comment.