From 6defd9c3a540698a54ab5445547b620a7a0c4395 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Wed, 19 Aug 2020 09:19:18 -0400 Subject: [PATCH 01/13] Trusted Apps initial setup for route registration --- .../common/endpoint/constants.ts | 2 ++ .../common/endpoint/schema/trusted_apps.ts | 14 ++++++++++ .../endpoint/{types.ts => types/index.ts} | 6 +++-- .../common/endpoint/types/trusted_apps.ts | 11 ++++++++ .../endpoint/endpoint_app_context_services.ts | 8 ++++++ .../endpoint/routes/trusted_apps/handlers.ts | 17 ++++++++++++ .../endpoint/routes/trusted_apps/index.ts | 26 +++++++++++++++++++ .../security_solution/server/plugin.ts | 3 +++ 8 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts rename x-pack/plugins/security_solution/common/endpoint/{types.ts => types/index.ts} (99%) create mode 100644 x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts create mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/index.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index 6ea0c36328eed..507ce63c7b815 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -11,3 +11,5 @@ export const policyIndexPattern = 'metrics-endpoint.policy-*'; export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*'; export const LIMITED_CONCURRENCY_ENDPOINT_ROUTE_TAG = 'endpoint:limited-concurrency'; export const LIMITED_CONCURRENCY_ENDPOINT_COUNT = 100; + +export const TRUSTED_APPS_LIST_API = '/api/endpoint/trusted_apps'; diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts new file mode 100644 index 0000000000000..410b9fc032e4c --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; + +export const GetTrustedAppsRequestSchema = { + query: schema.object({ + page: schema.maybe(schema.number({ defaultValue: 1, min: 1 })), + per_page: schema.maybe(schema.number({ defaultValue: 20 })), + }), +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/types.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts similarity index 99% rename from x-pack/plugins/security_solution/common/endpoint/types.ts rename to x-pack/plugins/security_solution/common/endpoint/types/index.ts index 2a1c95caff3a3..4253030727ab7 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -5,8 +5,10 @@ */ import { ApplicationStart } from 'kibana/public'; -import { NewPackageConfig, PackageConfig } from '../../../ingest_manager/common'; -import { ManifestSchema } from './schema/manifest'; +import { NewPackageConfig, PackageConfig } from '../../../../ingest_manager/common'; +import { ManifestSchema } from '../schema/manifest'; + +export * from './trusted_apps'; /** * Supported React-Router state for the Policy Details page diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts new file mode 100644 index 0000000000000..e3541cb1c6902 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { TypeOf } from '@kbn/config-schema'; +import { GetTrustedAppsRequestSchema } from '../schema/trusted_apps'; + +/** API request params for retrieving a list of Trusted Apps */ +export type GetTrustedAppsRequest = TypeOf; diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index f51e8c6be1040..cdc695a5ec2cd 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -12,10 +12,12 @@ import { import { AgentService, IngestManagerStartContract } from '../../../ingest_manager/server'; import { getPackageConfigCreateCallback } from './ingest_integration'; import { ManifestManager } from './services/artifacts'; +import { ExceptionListClient } from '../../../lists/server'; export type EndpointAppContextServiceStartContract = Partial< Pick > & { + exceptionsListService: ExceptionListClient; logger: Logger; manifestManager?: ManifestManager; registerIngestCallback?: IngestManagerStartContract['registerExternalCallback']; @@ -30,9 +32,11 @@ export class EndpointAppContextService { private agentService: AgentService | undefined; private manifestManager: ManifestManager | undefined; private savedObjectsStart: SavedObjectsServiceStart | undefined; + private exceptionsListService: ExceptionListClient | undefined; public start(dependencies: EndpointAppContextServiceStartContract) { this.agentService = dependencies.agentService; + this.exceptionsListService = dependencies.exceptionsListService; this.manifestManager = dependencies.manifestManager; this.savedObjectsStart = dependencies.savedObjectsStart; @@ -50,6 +54,10 @@ export class EndpointAppContextService { return this.agentService; } + public getExceptionsList() { + return this.exceptionsListService; + } + public getManifestManager(): ManifestManager | undefined { return this.manifestManager; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts new file mode 100644 index 0000000000000..a92448d745870 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RequestHandler } from 'kibana/server'; +import { GetTrustedAppsRequest } from '../../../../common/endpoint/types'; +import { EndpointAppContext } from '../../types'; + +export const getTrustedAppsListRouteHandler = ( + endpointAppContext: EndpointAppContext +): RequestHandler => { + return async (context, request, response) => { + return response.customError({ statusCode: 501 }); + }; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/index.ts new file mode 100644 index 0000000000000..178aa06eee877 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter } from 'kibana/server'; +import { GetTrustedAppsRequestSchema } from '../../../../common/endpoint/schema/trusted_apps'; +import { TRUSTED_APPS_LIST_API } from '../../../../common/endpoint/constants'; +import { getTrustedAppsListRouteHandler } from './handlers'; +import { EndpointAppContext } from '../../types'; + +export const registerTrustedAppsRoutes = ( + router: IRouter, + endpointAppContext: EndpointAppContext +) => { + // GET list + router.get( + { + path: TRUSTED_APPS_LIST_API, + validate: GetTrustedAppsRequestSchema, + options: { authRequired: true }, + }, + getTrustedAppsListRouteHandler(endpointAppContext) + ); +}; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index f2fad16d80414..ce454f1a72fc2 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -58,6 +58,7 @@ import { EndpointAppContext } from './endpoint/types'; import { registerDownloadExceptionListRoute } from './endpoint/routes/artifacts'; import { initUsageCollectors } from './usage'; import { AppRequestContext } from './types'; +import { registerTrustedAppsRoutes } from './endpoint/routes/trusted_apps'; export interface SetupPlugins { alerts: AlertingSetup; @@ -162,6 +163,7 @@ export class Plugin implements IPlugin Date: Wed, 19 Aug 2020 11:13:19 -0400 Subject: [PATCH 02/13] Added types for TrustedApp entries --- .../common/endpoint/types/trusted_apps.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index e3541cb1c6902..063b2e6bb3773 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -6,6 +6,20 @@ import { TypeOf } from '@kbn/config-schema'; import { GetTrustedAppsRequestSchema } from '../schema/trusted_apps'; +import { ExceptionListItemSchema } from '../../../../lists/common'; /** API request params for retrieving a list of Trusted Apps */ export type GetTrustedAppsRequest = TypeOf; + +/** Type for a new Trusted App Entry */ +export type NewTrustedApp = Pick< + ExceptionListItemSchema, + 'created_at' | 'created_by' | 'name' | 'description' | 'entries' +> & { + os: string; +}; + +/** A trusted app entry */ +export type TrustedApp = NewTrustedApp & { + id: string; +}; From a835bcac4f91583b162f6ca5ff09e0ff84250c60 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Wed, 19 Aug 2020 14:19:58 -0400 Subject: [PATCH 03/13] trusted apps list API returns results --- .../common/endpoint/schema/trusted_apps.ts | 2 +- .../common/endpoint/types/trusted_apps.ts | 9 +++- .../server/endpoint/mocks.ts | 2 + .../endpoint/routes/trusted_apps/handlers.ts | 39 +++++++++++++++-- .../endpoint/routes/trusted_apps/utils.ts | 42 +++++++++++++++++++ 5 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts index 410b9fc032e4c..20fab93aaf304 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts @@ -9,6 +9,6 @@ import { schema } from '@kbn/config-schema'; export const GetTrustedAppsRequestSchema = { query: schema.object({ page: schema.maybe(schema.number({ defaultValue: 1, min: 1 })), - per_page: schema.maybe(schema.number({ defaultValue: 20 })), + per_page: schema.maybe(schema.number({ defaultValue: 20, min: 1 })), }), }; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index 063b2e6bb3773..6ec88183e535a 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -7,9 +7,16 @@ import { TypeOf } from '@kbn/config-schema'; import { GetTrustedAppsRequestSchema } from '../schema/trusted_apps'; import { ExceptionListItemSchema } from '../../../../lists/common'; +import { FoundExceptionListItemSchema } from '../../../../lists/common/schemas/response'; /** API request params for retrieving a list of Trusted Apps */ -export type GetTrustedAppsRequest = TypeOf; +export type GetTrustedAppsListRequest = TypeOf; +export type GetTrustedListAppsResponse = Pick< + FoundExceptionListItemSchema, + 'per_page' | 'page' | 'total' +> & { + data: TrustedApp[]; +}; /** Type for a new Trusted App Entry */ export type NewTrustedApp = Pick< diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 9ca447d53bf45..138e3384f50d9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -21,6 +21,7 @@ import { import { ManifestManager } from './services/artifacts/manifest_manager/manifest_manager'; import { getManifestManagerMock } from './services/artifacts/manifest_manager/manifest_manager.mock'; import { EndpointAppContext } from './types'; +import { listMock } from '../../../lists/server/mocks'; /** * Creates a mocked EndpointAppContext. @@ -58,6 +59,7 @@ export const createMockEndpointAppContextServiceStartContract = (): jest.Mocked< > => { return { agentService: createMockAgentService(), + exceptionsListService: listMock.getExceptionListClient(), logger: loggingSystemMock.create().get('mock_endpoint_app_context'), savedObjectsStart: savedObjectsServiceMock.createStartContract(), manifestManager: getManifestManagerMock(), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts index a92448d745870..2514d22ae6c1d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts @@ -5,13 +5,44 @@ */ import { RequestHandler } from 'kibana/server'; -import { GetTrustedAppsRequest } from '../../../../common/endpoint/types'; +import { + GetTrustedAppsListRequest, + GetTrustedListAppsResponse, +} from '../../../../common/endpoint/types'; import { EndpointAppContext } from '../../types'; +import { exceptionItemToTrustedAppItem } from './utils'; export const getTrustedAppsListRouteHandler = ( endpointAppContext: EndpointAppContext -): RequestHandler => { - return async (context, request, response) => { - return response.customError({ statusCode: 501 }); +): RequestHandler => { + const exceptionsListService = endpointAppContext.service.getExceptionsList(); + const logger = endpointAppContext.logFactory.get('trusted_apps'); + + return async (context, req, res) => { + const { page, per_page: perPage } = req.query; + + // FIXME:PT call create list once PR merges + + try { + const results = await exceptionsListService?.findExceptionListItem({ + listId: 'trusted-apps', // FIXME:PT get value from const defined in pending PR + page, + perPage, + filter: '', + namespaceType: 'agnostic', + sortField: 'name', + sortOrder: 'asc', + }); + const body: GetTrustedListAppsResponse = { + data: results?.data.map(exceptionItemToTrustedAppItem) ?? [], + total: results?.total ?? 0, + page: results?.page ?? 1, + per_page: perPage!, + }; + return res.ok({ body }); + } catch (error) { + logger.error(error); + return res.internalError({ body: error }); + } }; }; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts new file mode 100644 index 0000000000000..d1e0e94b992dc --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ExceptionListItemSchema } from '../../../../../lists/common/shared_exports'; +import { TrustedApp } from '../../../../common/endpoint/types'; + +/** + * Map an ExcptionListItem to a TrustedApp item + * @param exceptionListItem + */ +export const exceptionItemToTrustedAppItem = ( + exceptionListItem: ExceptionListItemSchema +): TrustedApp => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { entries, description, created_by, created_at, name, _tags, id } = exceptionListItem; + const os = osFromTagsList(_tags); + return { + entries, + description, + created_at, + created_by, + name, + os, + id, + }; +}; + +/** + * Retrieves the OS entry from a list of tags (property returned with ExcptionListItem). + * For Trusted Apps each entry must have at MOST 1 OS. + * */ +const osFromTagsList = (tags: string[]): string => { + for (const tag of tags) { + if (tag.startsWith('os:')) { + return tag; + } + } + return ''; +}; From 0f4babab4caae0c68b4c13a2aacacbbdb8988ff5 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Wed, 19 Aug 2020 14:46:06 -0400 Subject: [PATCH 04/13] use methods and const from latest PR merge to lists --- .../server/endpoint/routes/trusted_apps/handlers.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts index 2514d22ae6c1d..02d1dc4da55f1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts @@ -11,6 +11,7 @@ import { } from '../../../../common/endpoint/types'; import { EndpointAppContext } from '../../types'; import { exceptionItemToTrustedAppItem } from './utils'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; export const getTrustedAppsListRouteHandler = ( endpointAppContext: EndpointAppContext @@ -21,11 +22,12 @@ export const getTrustedAppsListRouteHandler = ( return async (context, req, res) => { const { page, per_page: perPage } = req.query; - // FIXME:PT call create list once PR merges + // Ensure list is created if it does not exist + await exceptionsListService?.createTrustedAppsList(); try { const results = await exceptionsListService?.findExceptionListItem({ - listId: 'trusted-apps', // FIXME:PT get value from const defined in pending PR + listId: ENDPOINT_TRUSTED_APPS_LIST_ID, page, perPage, filter: '', From d0b6ea4f408830be84ec2bf40c661ab62bdc43f2 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Thu, 20 Aug 2020 14:58:59 -0400 Subject: [PATCH 05/13] a quick generator for trusted apps entries --- .../scripts/endpoint/load_trusted_apps.js | 8 ++ .../scripts/endpoint/trusted_apps/index.ts | 75 +++++++++++++++++++ .../endpoint/routes/trusted_apps/handlers.ts | 9 +-- 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js create mode 100644 x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts diff --git a/x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js b/x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js new file mode 100644 index 0000000000000..3034d82b4deb8 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +require('../../../../../src/setup_node_env'); +require('./trusted_apps').run(); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts new file mode 100644 index 0000000000000..bd7832e50194f --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { v4 as generateUUID } from 'uuid'; +import { KbnClient, ToolingLog } from '@kbn/dev-utils'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../lists/common/constants'; +import { TRUSTED_APPS_LIST_API } from '../../../common/endpoint/constants'; +import { ExceptionListItemSchema } from '../../../../lists/common/schemas/response'; + +interface RunOptions { + count?: number; +} + +export const run: (options?: RunOptions) => Promise = async ({ + count = 10, +}: RunOptions = {}) => { + const logger = new ToolingLog(); + // FIXME:PT use CLI param for kibana-url + const kbnClient = new KbnClient(logger, { url: 'http://elastic:changeme@localhost:5601' }); + + // touch the Trusted Apps List so it can be created + await kbnClient.request({ + method: 'GET', + path: TRUSTED_APPS_LIST_API, + }); + + return Promise.all( + Array.from({ length: count }, () => { + return kbnClient + .request({ + method: 'POST', + path: '/api/exception_lists/items', + body: generateTrustedAppEntry(), + }) + .then((item) => (item as unknown) as ExceptionListItemSchema); + }) + ); +}; + +interface GenerateTrustedAppEntryOptions { + os?: 'windows' | 'macos' | 'linux'; + name?: string; +} + +const generateTrustedAppEntry: (options?: GenerateTrustedAppEntryOptions) => object = ({ + os = 'windows', + name = `Sample Endpoint Trusted App Entry ${Date.now()}`, +} = {}) => { + return { + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + item_id: `generator_endpoint_trusted_apps_${generateUUID()}`, + _tags: ['endpoint', `os:${os}`], + tags: ['user added string for a tag', 'malware'], + type: 'simple', + description: 'This is a sample agnostic endpoint trusted app entry', + name, + namespace_type: 'agnostic', + entries: [ + { + field: 'actingProcess.file.signer', + operator: 'included', + type: 'match', + value: 'Elastic, N.V.', + }, + { + field: 'actingProcess.file.path', + operator: 'included', + type: 'match', + value: '/one/two/three', + }, + ], + }; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts index 02d1dc4da55f1..543d43eb1ee63 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts @@ -16,21 +16,20 @@ import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/const export const getTrustedAppsListRouteHandler = ( endpointAppContext: EndpointAppContext ): RequestHandler => { - const exceptionsListService = endpointAppContext.service.getExceptionsList(); const logger = endpointAppContext.logFactory.get('trusted_apps'); return async (context, req, res) => { + const exceptionsListService = endpointAppContext.service.getExceptionsList(); const { page, per_page: perPage } = req.query; - // Ensure list is created if it does not exist - await exceptionsListService?.createTrustedAppsList(); - try { + // Ensure list is created if it does not exist + await exceptionsListService?.createTrustedAppsList(); const results = await exceptionsListService?.findExceptionListItem({ listId: ENDPOINT_TRUSTED_APPS_LIST_ID, page, perPage, - filter: '', + filter: undefined, namespaceType: 'agnostic', sortField: 'name', sortOrder: 'asc', From 0b979496234dbef8cbfdc566d461e94a46b284ad Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Thu, 20 Aug 2020 16:33:53 -0400 Subject: [PATCH 06/13] support cli options for trusted app data loader --- .../common/endpoint/types/trusted_apps.ts | 12 +++++------ .../scripts/endpoint/load_trusted_apps.js | 3 ++- .../scripts/endpoint/trusted_apps/index.ts | 20 +++++++++++++++++-- 3 files changed, 25 insertions(+), 10 deletions(-) mode change 100644 => 100755 x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index 6ec88183e535a..c6e25c412a009 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -19,14 +19,12 @@ export type GetTrustedListAppsResponse = Pick< }; /** Type for a new Trusted App Entry */ -export type NewTrustedApp = Pick< - ExceptionListItemSchema, - 'created_at' | 'created_by' | 'name' | 'description' | 'entries' -> & { +export type NewTrustedApp = Pick & { os: string; }; /** A trusted app entry */ -export type TrustedApp = NewTrustedApp & { - id: string; -}; +export type TrustedApp = NewTrustedApp & + Pick & { + id: string; + }; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js b/x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js old mode 100644 new mode 100755 index 3034d82b4deb8..872639dd9fb7e --- a/x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js +++ b/x-pack/plugins/security_solution/scripts/endpoint/load_trusted_apps.js @@ -1,3 +1,4 @@ +#!/usr/bin/env node /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License; @@ -5,4 +6,4 @@ */ require('../../../../../src/setup_node_env'); -require('./trusted_apps').run(); +require('./trusted_apps').cli(); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts index bd7832e50194f..3bd27259ad80c 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { v4 as generateUUID } from 'uuid'; +// @ts-ignore +import minimist from 'minimist'; import { KbnClient, ToolingLog } from '@kbn/dev-utils'; import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../lists/common/constants'; import { TRUSTED_APPS_LIST_API } from '../../../common/endpoint/constants'; @@ -13,11 +15,25 @@ interface RunOptions { count?: number; } +const logger = new ToolingLog({ level: 'info', writeTo: process.stdout }); +const separator = '----------------------------------------'; + +export const cli = async () => { + const options: RunOptions = minimist(process.argv.slice(2), { + default: { + count: 10, + }, + }); + logger.write(`${separator} +Loading ${options.count} Trusted App Entries`); + await run(options); + logger.write(`Done! +${separator}`); +}; + export const run: (options?: RunOptions) => Promise = async ({ count = 10, }: RunOptions = {}) => { - const logger = new ToolingLog(); - // FIXME:PT use CLI param for kibana-url const kbnClient = new KbnClient(logger, { url: 'http://elastic:changeme@localhost:5601' }); // touch the Trusted Apps List so it can be created From 6c94624ba565f4f2f07ce68159fd6ed1779c2252 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 24 Aug 2020 11:10:05 -0400 Subject: [PATCH 07/13] Add mocked `createTrustedAppsList()` method to `ExceptionListClientMock` --- .../schemas/response/exception_list_schema.mock.ts | 14 ++++++++++++++ .../exception_lists/exception_list_client.mock.ts | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts index e2f0a7c06b400..e01edd9751ecf 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts @@ -19,6 +19,11 @@ import { _VERSION, } from '../../constants.mock'; import { ENDPOINT_LIST_ID } from '../..'; +import { + ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, + ENDPOINT_TRUSTED_APPS_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_NAME, +} from '../../constants'; import { ExceptionListSchema } from './exception_list_schema'; @@ -42,6 +47,15 @@ export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ version: VERSION, }); +export const getTrustedAppsSchemaMock = (): ExceptionListSchema => { + return { + ...getExceptionListSchemaMock(), + description: ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + name: ENDPOINT_TRUSTED_APPS_LIST_NAME, + }; +}; + /** * This is useful for end to end tests where we remove the auto generated parts for comparisons * such as created_at, updated_at, and id. diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts index d0e238f8c5c40..c7599cd83cbba 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts @@ -9,7 +9,10 @@ import { savedObjectsClientMock } from 'src/core/server/mocks'; import { getFoundExceptionListSchemaMock } from '../../../common/schemas/response/found_exception_list_schema.mock'; import { getFoundExceptionListItemSchemaMock } from '../../../common/schemas/response/found_exception_list_item_schema.mock'; import { getExceptionListItemSchemaMock } from '../../../common/schemas/response/exception_list_item_schema.mock'; -import { getExceptionListSchemaMock } from '../../../common/schemas/response/exception_list_schema.mock'; +import { + getExceptionListSchemaMock, + getTrustedAppsSchemaMock, +} from '../../../common/schemas/response/exception_list_schema.mock'; import { ExceptionListClient } from './exception_list_client'; @@ -24,6 +27,7 @@ export class ExceptionListClientMock extends ExceptionListClient { public deleteExceptionListItem = jest.fn().mockResolvedValue(getExceptionListItemSchemaMock()); public findExceptionListItem = jest.fn().mockResolvedValue(getFoundExceptionListItemSchemaMock()); public findExceptionList = jest.fn().mockResolvedValue(getFoundExceptionListSchemaMock()); + public createTrustedAppsList = jest.fn().mockResolvedValue(getTrustedAppsSchemaMock()); } export const getExceptionListClientMock = (): ExceptionListClient => { From fafa9d6dbee62a830fdff2c738eaca3c2b78da48 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 24 Aug 2020 12:00:30 -0400 Subject: [PATCH 08/13] tests fro trusted apps route handlers --- .../routes/trusted_apps/trusted_apps.test.ts | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts new file mode 100644 index 0000000000000..70a14d4b61173 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EndpointAppContextService } from '../../endpoint_app_context_services'; +import { + createMockEndpointAppContext, + createMockEndpointAppContextServiceStartContract, +} from '../../mocks'; +import { IRouter, RequestHandler, RouteConfig } from 'kibana/server'; +import { httpServerMock, httpServiceMock } from '../../../../../../../src/core/server/mocks'; +import { registerTrustedAppsRoutes } from './index'; +import { TRUSTED_APPS_LIST_API } from '../../../../common/endpoint/constants'; +import { GetTrustedAppsListRequest } from '../../../../common/endpoint/types'; +import { xpackMocks } from '../../../../../../mocks'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; +import { EndpointAppContext } from '../../types'; + +describe('when invoking endpoint trusted apps route handlers', () => { + let routerMock: jest.Mocked; + let endpointAppContextService: EndpointAppContextService; + let context: ReturnType; + let response: ReturnType; + let exceptionsListClient: ReturnType< + typeof createMockEndpointAppContextServiceStartContract + >['exceptionsListService']; + let endpointAppContext: EndpointAppContext; + + beforeEach(() => { + routerMock = httpServiceMock.createRouter(); + endpointAppContextService = new EndpointAppContextService(); + const startContract = createMockEndpointAppContextServiceStartContract(); + exceptionsListClient = startContract.exceptionsListService; + endpointAppContextService.start(startContract); + endpointAppContext = { + ...createMockEndpointAppContext(), + service: endpointAppContextService, + }; + registerTrustedAppsRoutes(routerMock, endpointAppContext); + + // For use in individual API calls + context = xpackMocks.createRequestHandlerContext(); + response = httpServerMock.createResponseFactory(); + }); + + describe('when fetching list of trusted apps', () => { + let routeConfig: RouteConfig; + let routeHandler: RequestHandler; + const createListRequest = (page: number = 1, perPage: number = 20) => { + return httpServerMock.createKibanaRequest({ + path: TRUSTED_APPS_LIST_API, + method: 'get', + query: { + page, + per_page: perPage, + }, + }); + }; + + beforeEach(() => { + // Get the registered List handler from the IRouter instance + [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => + path.startsWith(TRUSTED_APPS_LIST_API) + )!; + }); + + it('should create the Trusted Apps List first', async () => { + const request = createListRequest(); + await routeHandler(context, request, response); + expect(exceptionsListClient.createTrustedAppsList).toHaveBeenCalled(); + expect(response.ok).toHaveBeenCalled(); + }); + + it('should pass pagination query params to exception list service', async () => { + const request = createListRequest(10, 100); + const emptyResponse = { + data: [], + page: 10, + per_page: 100, + total: 0, + }; + + exceptionsListClient.findExceptionListItem.mockResolvedValue(emptyResponse); + await routeHandler(context, request, response); + + expect(response.ok).toHaveBeenCalledWith({ body: emptyResponse }); + expect(exceptionsListClient.findExceptionListItem).toHaveBeenCalledWith({ + listId: ENDPOINT_TRUSTED_APPS_LIST_ID, + page: 10, + perPage: 100, + filter: undefined, + namespaceType: 'agnostic', + sortField: 'name', + sortOrder: 'asc', + }); + }); + + it('should log unexpected error if one occurs', async () => { + exceptionsListClient.findExceptionListItem.mockImplementation(() => { + throw new Error('expected error'); + }); + const request = createListRequest(10, 100); + await routeHandler(context, request, response); + expect(response.internalError).toHaveBeenCalled(); + expect(endpointAppContext.logFactory.get('trusted_apps').error).toHaveBeenCalled(); + }); + }); +}); From c66077bfe59376072d1292eb10832e4285cc4fc7 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 24 Aug 2020 12:30:51 -0400 Subject: [PATCH 09/13] tests for trusted apps schema --- .../endpoint/schema/trusted_apps.test.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts new file mode 100644 index 0000000000000..7aec8e15c317c --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { GetTrustedAppsRequestSchema } from './trusted_apps'; + +describe('When invoking Trusted Apps Schema', () => { + describe('for GET List', () => { + const getListQueryParams = (page: unknown = 1, perPage: unknown = 20) => ({ + page, + per_page: perPage, + }); + const query = GetTrustedAppsRequestSchema.query; + + describe('query param validation', () => { + it('should return query params if valid', () => { + expect(query.validate(getListQueryParams())).toEqual({ + page: 1, + per_page: 20, + }); + }); + + it('should use default values', () => { + expect(query.validate(getListQueryParams(undefined, undefined))).toEqual({ + page: 1, + per_page: 20, + }); + expect(query.validate(getListQueryParams(undefined, 100))).toEqual({ + page: 1, + per_page: 100, + }); + expect(query.validate(getListQueryParams(10, undefined))).toEqual({ + page: 10, + per_page: 20, + }); + }); + + it('should throw if `page` param is not a number', () => { + expect(() => { + query.validate(getListQueryParams('one')); + }).toThrowError(); + }); + + it('should throw if `page` param is less than 1', () => { + expect(() => { + query.validate(getListQueryParams(0)); + }).toThrowError(); + expect(() => { + query.validate(getListQueryParams(-1)); + }).toThrowError(); + }); + + it('should throw if `per_page` param is not a number', () => { + expect(() => { + query.validate(getListQueryParams(1, 'twenty')); + }).toThrowError(); + }); + + it('should throw if `per_page` param is less than 1', () => { + expect(() => { + query.validate(getListQueryParams(1, 0)); + }).toThrowError(); + expect(() => { + query.validate(getListQueryParams(1, -1)); + }).toThrowError(); + }); + }); + }); +}); From 697a57b4239ac485095e6cb8d15a471eb09940cb Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 24 Aug 2020 12:31:42 -0400 Subject: [PATCH 10/13] Correct name of mock method --- .../common/schemas/response/exception_list_schema.mock.ts | 2 +- .../services/exception_lists/exception_list_client.mock.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts index e01edd9751ecf..6df051e83b97c 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts @@ -47,7 +47,7 @@ export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ version: VERSION, }); -export const getTrustedAppsSchemaMock = (): ExceptionListSchema => { +export const getTrustedAppsListSchemaMock = (): ExceptionListSchema => { return { ...getExceptionListSchemaMock(), description: ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts index c7599cd83cbba..4354c735747be 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts @@ -11,7 +11,7 @@ import { getFoundExceptionListItemSchemaMock } from '../../../common/schemas/res import { getExceptionListItemSchemaMock } from '../../../common/schemas/response/exception_list_item_schema.mock'; import { getExceptionListSchemaMock, - getTrustedAppsSchemaMock, + getTrustedAppsListSchemaMock, } from '../../../common/schemas/response/exception_list_schema.mock'; import { ExceptionListClient } from './exception_list_client'; @@ -27,7 +27,7 @@ export class ExceptionListClientMock extends ExceptionListClient { public deleteExceptionListItem = jest.fn().mockResolvedValue(getExceptionListItemSchemaMock()); public findExceptionListItem = jest.fn().mockResolvedValue(getFoundExceptionListItemSchemaMock()); public findExceptionList = jest.fn().mockResolvedValue(getFoundExceptionListSchemaMock()); - public createTrustedAppsList = jest.fn().mockResolvedValue(getTrustedAppsSchemaMock()); + public createTrustedAppsList = jest.fn().mockResolvedValue(getTrustedAppsListSchemaMock()); } export const getExceptionListClientMock = (): ExceptionListClient => { From ae8d8767d9c04f3782a0d6e171ec23e3e6cb86aa Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 24 Aug 2020 12:38:31 -0400 Subject: [PATCH 11/13] Fix service to ensure return value of `getExceptionList` service throws if service not available --- .../server/endpoint/endpoint_app_context_services.ts | 3 +++ .../server/endpoint/routes/trusted_apps/handlers.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index f1a6f5b83e371..6a8d56ff41a04 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -55,6 +55,9 @@ export class EndpointAppContextService { } public getExceptionsList() { + if (!this.exceptionsListService) { + throw new Error('exceptionsListService not set'); + } return this.exceptionsListService; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts index 543d43eb1ee63..12901e7c655d1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts @@ -25,7 +25,7 @@ export const getTrustedAppsListRouteHandler = ( try { // Ensure list is created if it does not exist await exceptionsListService?.createTrustedAppsList(); - const results = await exceptionsListService?.findExceptionListItem({ + const results = await exceptionsListService.findExceptionListItem({ listId: ENDPOINT_TRUSTED_APPS_LIST_ID, page, perPage, From c7176477743d01f17e9569214d409f716792bbbb Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 24 Aug 2020 14:26:19 -0400 Subject: [PATCH 12/13] Fix types --- .../routes/trusted_apps/trusted_apps.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts index 70a14d4b61173..1d4a7919b89f5 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts @@ -9,7 +9,7 @@ import { createMockEndpointAppContext, createMockEndpointAppContextServiceStartContract, } from '../../mocks'; -import { IRouter, RequestHandler, RouteConfig } from 'kibana/server'; +import { IRouter, RequestHandler } from 'kibana/server'; import { httpServerMock, httpServiceMock } from '../../../../../../../src/core/server/mocks'; import { registerTrustedAppsRoutes } from './index'; import { TRUSTED_APPS_LIST_API } from '../../../../common/endpoint/constants'; @@ -17,22 +17,21 @@ import { GetTrustedAppsListRequest } from '../../../../common/endpoint/types'; import { xpackMocks } from '../../../../../../mocks'; import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; import { EndpointAppContext } from '../../types'; +import { ExceptionListClient } from '../../../../../lists/server'; describe('when invoking endpoint trusted apps route handlers', () => { let routerMock: jest.Mocked; let endpointAppContextService: EndpointAppContextService; let context: ReturnType; let response: ReturnType; - let exceptionsListClient: ReturnType< - typeof createMockEndpointAppContextServiceStartContract - >['exceptionsListService']; + let exceptionsListClient: jest.Mocked; let endpointAppContext: EndpointAppContext; beforeEach(() => { routerMock = httpServiceMock.createRouter(); endpointAppContextService = new EndpointAppContextService(); const startContract = createMockEndpointAppContextServiceStartContract(); - exceptionsListClient = startContract.exceptionsListService; + exceptionsListClient = startContract.exceptionsListService as jest.Mocked; endpointAppContextService.start(startContract); endpointAppContext = { ...createMockEndpointAppContext(), @@ -46,7 +45,6 @@ describe('when invoking endpoint trusted apps route handlers', () => { }); describe('when fetching list of trusted apps', () => { - let routeConfig: RouteConfig; let routeHandler: RequestHandler; const createListRequest = (page: number = 1, perPage: number = 20) => { return httpServerMock.createKibanaRequest({ @@ -61,7 +59,7 @@ describe('when invoking endpoint trusted apps route handlers', () => { beforeEach(() => { // Get the registered List handler from the IRouter instance - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => + [, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => path.startsWith(TRUSTED_APPS_LIST_API) )!; }); From b97524b39e2f9e667ac5fdb62623b184f8a50f83 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Wed, 26 Aug 2020 11:29:14 -0400 Subject: [PATCH 13/13] Refactor TrustedApp type + code review feedback --- .../common/endpoint/types/trusted_apps.ts | 50 +++++++++++++------ .../endpoint/routes/trusted_apps/handlers.ts | 2 +- .../endpoint/routes/trusted_apps/utils.ts | 8 +-- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index c6e25c412a009..2905274bef1cb 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -6,25 +6,47 @@ import { TypeOf } from '@kbn/config-schema'; import { GetTrustedAppsRequestSchema } from '../schema/trusted_apps'; -import { ExceptionListItemSchema } from '../../../../lists/common'; -import { FoundExceptionListItemSchema } from '../../../../lists/common/schemas/response'; /** API request params for retrieving a list of Trusted Apps */ export type GetTrustedAppsListRequest = TypeOf; -export type GetTrustedListAppsResponse = Pick< - FoundExceptionListItemSchema, - 'per_page' | 'page' | 'total' -> & { +export interface GetTrustedListAppsResponse { + per_page: number; + page: number; + total: number; data: TrustedApp[]; -}; +} + +interface MacosLinuxConditionEntry { + field: 'hash' | 'path'; + type: 'match'; + operator: 'included'; + value: string; +} + +type WindowsConditionEntry = + | MacosLinuxConditionEntry + | (Omit & { + field: 'signer'; + }); /** Type for a new Trusted App Entry */ -export type NewTrustedApp = Pick & { - os: string; -}; +export type NewTrustedApp = { + name: string; + description?: string; +} & ( + | { + os: 'linux' | 'macos'; + entries: MacosLinuxConditionEntry[]; + } + | { + os: 'windows'; + entries: WindowsConditionEntry[]; + } +); /** A trusted app entry */ -export type TrustedApp = NewTrustedApp & - Pick & { - id: string; - }; +export type TrustedApp = NewTrustedApp & { + id: string; + created_at: string; + created_by: string; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts index 12901e7c655d1..6c29a2244c203 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts @@ -38,7 +38,7 @@ export const getTrustedAppsListRouteHandler = ( data: results?.data.map(exceptionItemToTrustedAppItem) ?? [], total: results?.total ?? 0, page: results?.page ?? 1, - per_page: perPage!, + per_page: results?.per_page ?? perPage!, }; return res.ok({ body }); } catch (error) { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts index d1e0e94b992dc..2b417a4c6a8e1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/utils.ts @@ -25,18 +25,18 @@ export const exceptionItemToTrustedAppItem = ( name, os, id, - }; + } as TrustedApp; }; /** * Retrieves the OS entry from a list of tags (property returned with ExcptionListItem). * For Trusted Apps each entry must have at MOST 1 OS. * */ -const osFromTagsList = (tags: string[]): string => { +const osFromTagsList = (tags: string[]): TrustedApp['os'] | 'unknown' => { for (const tag of tags) { if (tag.startsWith('os:')) { - return tag; + return tag.substr(3) as TrustedApp['os']; } } - return ''; + return 'unknown'; };