[Security Solution] Explicit request and response schemas for rules management endpoints (#162324)

**Related to: https://github.com/elastic/security-team/issues/7098**

### Summary

- Move Rules Management HTTP API schemas to `/common/api`
- Explicitly define response types for API endpoints
- Remove the `_generate_assets` endpoint as unused
- Minor type fixes
This commit is contained in:
Dmitrii Shevchenko 2023-07-26 18:00:55 +02:00 committed by GitHub
parent 708fd851a6
commit 0d5a206430
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 173 additions and 243 deletions

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { fold, Either, mapLeft } from 'fp-ts/lib/Either';
import { Either, isLeft, mapLeft } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { fromEither, TaskEither } from 'fp-ts/lib/TaskEither';
import * as t from 'io-ts';
@ -16,28 +16,27 @@ import { formatErrors } from '../format_errors';
export const validate = <T extends t.Mixed>(
obj: object,
schema: T
): [t.TypeOf<T> | null, string | null] => {
): [t.TypeOf<T>, null] | [null, string] => {
const decoded = schema.decode(obj);
const checked = exactCheck(obj, decoded);
const left = (errors: t.Errors): [T | null, string | null] => [
null,
formatErrors(errors).join(','),
];
const right = (output: T): [T | null, string | null] => [output, null];
return pipe(checked, fold(left, right));
if (isLeft(checked)) {
return [null, formatErrors(checked.left).join(',')];
} else {
return [checked.right, null];
}
};
export const validateNonExact = <T extends t.Mixed>(
obj: unknown,
schema: T
): [t.TypeOf<T> | null, string | null] => {
): [t.TypeOf<T>, null] | [null, string] => {
const decoded = schema.decode(obj);
const left = (errors: t.Errors): [T | null, string | null] => [
null,
formatErrors(errors).join(','),
];
const right = (output: T): [T | null, string | null] => [output, null];
return pipe(decoded, fold(left, right));
if (isLeft(decoded)) {
return [null, formatErrors(decoded.left).join(',')];
} else {
return [decoded.right, null];
}
};
export const validateEither = <T extends t.Mixed, A extends unknown>(

View file

@ -21,6 +21,3 @@ export const REVIEW_RULE_UPGRADE_URL = `${NEW_BASE_URL}/upgrade/_review` as cons
export const PERFORM_RULE_UPGRADE_URL = `${NEW_BASE_URL}/upgrade/_perform` as const;
export const REVIEW_RULE_INSTALLATION_URL = `${NEW_BASE_URL}/installation/_review` as const;
export const PERFORM_RULE_INSTALLATION_URL = `${NEW_BASE_URL}/installation/_perform` as const;
// Helper endpoints for development and testing. Should be removed later.
export const GENERATE_ASSETS_URL = `${NEW_BASE_URL}/_generate_assets` as const;

View file

@ -265,3 +265,7 @@ export interface BulkEditActionErrorResponse {
}
export type BulkEditActionResponse = BulkEditActionSuccessResponse | BulkEditActionErrorResponse;
export type BulkExportActionResponse = string;
export type PerformBulkActionResponse = BulkEditActionResponse | BulkExportActionResponse;

View file

@ -6,7 +6,10 @@
*/
import type * as t from 'io-ts';
import { RuleCreateProps } from '../../../model';
import { RuleCreateProps, RuleResponse } from '../../../model';
export const CreateRuleRequestBody = RuleCreateProps;
export type CreateRuleRequestBody = t.TypeOf<typeof CreateRuleRequestBody>;
export const CreateRuleResponse = RuleResponse;
export type CreateRuleResponse = t.TypeOf<typeof CreateRuleResponse>;

View file

@ -0,0 +1,12 @@
/*
* 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 * as t from 'io-ts';
import { RuleResponse } from '../../../model';
export const DeleteRuleResponse = RuleResponse;
export type DeleteRuleResponse = t.TypeOf<typeof DeleteRuleResponse>;

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import { RulePatchProps, ThresholdRulePatchProps } from '../../../model';
import type * as t from 'io-ts';
import { RulePatchProps, RuleResponse, ThresholdRulePatchProps } from '../../../model';
/**
* Request body parameters of the API route.
@ -16,3 +17,6 @@ export const PatchRuleRequestBody = RulePatchProps;
export type ThresholdPatchRuleRequestBody = ThresholdRulePatchProps;
export const ThresholdPatchRuleRequestBody = ThresholdRulePatchProps;
export const PatchRuleResponse = RuleResponse;
export type PatchRuleResponse = t.TypeOf<typeof PatchRuleResponse>;

View file

@ -6,7 +6,11 @@
*/
import type * as t from 'io-ts';
import { RuleResponse } from '../../../model';
import { QueryRuleByIds } from '../../model/query_rule_by_ids';
export const ReadRuleRequestQuery = QueryRuleByIds;
export type ReadRuleRequestQuery = t.TypeOf<typeof ReadRuleRequestQuery>;
export const ReadRuleResponse = RuleResponse;
export type ReadRuleResponse = t.TypeOf<typeof ReadRuleResponse>;

View file

@ -6,7 +6,10 @@
*/
import type * as t from 'io-ts';
import { RuleUpdateProps } from '../../../model';
import { RuleResponse, RuleUpdateProps } from '../../../model';
export const UpdateRuleRequestBody = RuleUpdateProps;
export type UpdateRuleRequestBody = t.TypeOf<typeof UpdateRuleRequestBody>;
export const UpdateRuleResponse = RuleResponse;
export type UpdateRuleResponse = t.TypeOf<typeof UpdateRuleResponse>;

View file

@ -10,7 +10,6 @@ import { pipe } from 'fp-ts/lib/pipeable';
import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
import { ExportRulesRequestBody, ExportRulesRequestQuery } from './export_rules_route';
import type { ExportRulesRequestQueryDecoded } from './export_rules_route';
describe('Export rules request schema', () => {
describe('ExportRulesRequestBody', () => {
@ -81,7 +80,7 @@ describe('Export rules request schema', () => {
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ExportRulesRequestQueryDecoded = {
const expected: ExportRulesRequestQuery = {
file_name: 'export.ndjson',
exclude_export_details: false,
};
@ -98,7 +97,7 @@ describe('Export rules request schema', () => {
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ExportRulesRequestQueryDecoded = {
const expected: ExportRulesRequestQuery = {
file_name: 'test.ndjson',
exclude_export_details: false,
};
@ -129,7 +128,7 @@ describe('Export rules request schema', () => {
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ExportRulesRequestQueryDecoded = {
const expected: ExportRulesRequestQuery = {
exclude_export_details: true,
file_name: 'export.ndjson',
};

View file

@ -9,7 +9,6 @@ import * as t from 'io-ts';
import { DefaultExportFileName } from '@kbn/securitysolution-io-ts-alerting-types';
import { DefaultStringBooleanFalse } from '@kbn/securitysolution-io-ts-types';
import type { FileName, ExcludeExportDetails } from '../../model';
import { RuleSignatureId } from '../../model';
const ObjectsWithRuleId = t.array(t.exact(t.type({ rule_id: RuleSignatureId })));
@ -30,11 +29,3 @@ export type ExportRulesRequestQuery = t.TypeOf<typeof ExportRulesRequestQuery>;
export const ExportRulesRequestQuery = t.exact(
t.partial({ file_name: DefaultExportFileName, exclude_export_details: DefaultStringBooleanFalse })
);
export type ExportRulesRequestQueryDecoded = Omit<
ExportRulesRequestQuery,
'file_name' | 'exclude_export_details'
> & {
file_name: FileName;
exclude_export_details: ExcludeExportDetails;
};

View file

@ -9,7 +9,7 @@ import { left } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
import { FindRulesRequestQuery } from './request_schema';
import { FindRulesRequestQuery } from './find_rules_route';
describe('Find rules request schema', () => {
test('empty objects do validate', () => {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { FindRulesRequestQuery } from './request_schema';
import type { FindRulesRequestQuery } from './find_rules_route';
import { validateFindRulesRequestQuery } from './request_schema_validation';
describe('Find rules request schema, additional validation', () => {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { FindRulesRequestQuery } from './request_schema';
import type { FindRulesRequestQuery } from './find_rules_route';
/**
* Additional validation that is implemented outside of the schema itself.

View file

@ -12,20 +12,23 @@ export * from './bulk_crud/bulk_patch_rules/bulk_patch_rules_route';
export * from './bulk_crud/bulk_update_rules/bulk_update_rules_route';
export * from './bulk_crud/response_schema';
export * from './coverage_overview/coverage_overview_route';
export * from './crud/create_rule/create_rule_route';
export * from './crud/create_rule/request_schema_validation';
export * from './crud/patch_rule/request_schema_validation';
export * from './crud/delete_rule/delete_rule_route';
export * from './crud/patch_rule/patch_rule_route';
export * from './crud/patch_rule/request_schema_validation';
export * from './crud/read_rule/read_rule_route';
export * from './crud/update_rule/update_rule_route';
export * from './crud/update_rule/request_schema_validation';
export * from './crud/update_rule/update_rule_route';
export * from './export_rules/export_rules_details_schema';
export * from './export_rules/export_rules_route';
export * from './get_rule_management_filters/get_rule_management_filters_route';
export * from './find_rules/request_schema';
export * from './find_rules/find_rules_route';
export * from './find_rules/request_schema_validation';
export * from './get_rule_management_filters/get_rule_management_filters_route';
export * from './import_rules/import_rules_route';
export * from './import_rules/rule_to_import_validation';
export * from './import_rules/rule_to_import';
export * from './urls';
export * from './model/query_rule_by_ids';
export * from './model/query_rule_by_ids_validation';
export * from './model/query_rule_by_ids';
export * from './urls';
export * from './tags/read_tags/read_tags_route';

View file

@ -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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import * as t from 'io-ts';
export const ReadTagsResponse = t.array(t.string);
export type ReadTagsResponse = t.TypeOf<typeof ReadTagsResponse>;

View file

@ -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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import * as t from 'io-ts';
export const SetupHealthResponse = t.exact(t.type({}));
export type SetupHealthResponse = t.TypeOf<typeof SetupHealthResponse>;

View file

@ -8,6 +8,7 @@
export * from './detection_engine_health/get_cluster_health/get_cluster_health_route';
export * from './detection_engine_health/get_rule_health/get_rule_health_route';
export * from './detection_engine_health/get_space_health/get_space_health_route';
export * from './detection_engine_health/setup_health/setup_health_route';
export * from './detection_engine_health/model';
export * from './rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route';
export * from './rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route';

View file

@ -1,119 +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 * as t from 'io-ts';
import moment from 'moment';
import { transformError } from '@kbn/securitysolution-es-utils';
import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types';
import { GENERATE_ASSETS_URL } from '../../../../../../common/api/detection_engine/prebuilt_rules';
import type { SecuritySolutionPluginRouter } from '../../../../../types';
import { buildRouteValidation } from '../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../routes/utils';
import type { PrebuiltRuleAsset } from '../../model/rule_assets/prebuilt_rule_asset';
import { createPrebuiltRuleAssetsClient } from '../../logic/rule_assets/prebuilt_rule_assets_client';
type RequestBody = t.TypeOf<typeof RequestBody>;
const RequestBody = t.exact(
t.type({
num_versions_per_rule: PositiveIntegerGreaterThanZero,
})
);
/**
* NOTE: This is a helper endpoint for development and testing. It should be removed later.
* This endpoint:
* - reads currently installed latest assets (saved objects of type security-rule)
* - generates more versions of rule assets based on the latest ones (multiple versions per rule)
* - writes the generated saved objects back to the kibana index
*/
export const generateAssetsRoute = (router: SecuritySolutionPluginRouter) => {
router.post(
{
path: GENERATE_ASSETS_URL,
validate: {
body: buildRouteValidation(RequestBody),
},
options: {
tags: ['access:securitySolution'],
timeout: {
// FUNFACT: If we do not add a very long timeout what will happen
// is that Chrome which receive a 408 error and then do a retry.
// This retry can cause lots of connections to happen. Using a very
// long timeout will ensure that Chrome does not do retries and saturate the connections.
idleSocket: moment.duration('1', 'hour').asMilliseconds(),
},
},
},
async (context, request, response) => {
const siemResponse = buildSiemResponse(response);
try {
const ctx = await context.resolve(['core']);
const soClient = ctx.core.savedObjects.client;
const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient);
const latestRules = await ruleAssetsClient.fetchLatestAssets();
const historicalRules = generateHistoricalVersionsForManyRules(
latestRules,
request.body.num_versions_per_rule
);
await ruleAssetsClient.bulkCreateAssets(historicalRules);
return response.ok({
body: {
num_latest_rules: latestRules.length,
num_installed_versions: historicalRules.length,
},
});
} catch (err) {
const error = transformError(err);
return siemResponse.error({
body: error.message,
statusCode: error.statusCode,
});
}
}
);
};
const generateHistoricalVersionsForManyRules = (
rules: PrebuiltRuleAsset[],
numberOfVersionsPerRule: number
) => {
const result: PrebuiltRuleAsset[] = [];
rules.forEach((rule) => {
result.push(...generateHistoricalVersionsForOneRule(rule, numberOfVersionsPerRule));
});
return result;
};
const generateHistoricalVersionsForOneRule = (
rule: PrebuiltRuleAsset,
numberOfVersionsPerRule: number
): PrebuiltRuleAsset[] => {
const { name: ruleName, version: latestVersion, ...restOfRuleAttributes } = rule;
const nextToLatestVersion = latestVersion + 1;
const result: PrebuiltRuleAsset[] = [];
for (let i = 0; i < numberOfVersionsPerRule; i++) {
const historicalVersion = nextToLatestVersion + i;
result.push({
name: `${ruleName} v${historicalVersion}`,
version: historicalVersion,
...restOfRuleAttributes,
});
}
return result;
};

View file

@ -11,7 +11,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../types';
import { getPrebuiltRulesAndTimelinesStatusRoute } from './get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route';
import { getPrebuiltRulesStatusRoute } from './get_prebuilt_rules_status/get_prebuilt_rules_status_route';
import { installPrebuiltRulesAndTimelinesRoute } from './install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route';
import { generateAssetsRoute } from './generate_assets/generate_assets_route';
import { reviewRuleInstallationRoute } from './review_rule_installation/review_rule_installation_route';
import { reviewRuleUpgradeRoute } from './review_rule_upgrade/review_rule_upgrade_route';
import { performRuleInstallationRoute } from './perform_rule_installation/perform_rule_installation_route';
@ -31,7 +30,4 @@ export const registerPrebuiltRulesRoutes = (
performRuleUpgradeRoute(router);
reviewRuleInstallationRoute(router);
reviewRuleUpgradeRoute(router);
// Helper endpoints for development and testing. Should be removed later.
generateAssetsRoute(router);
};

View file

@ -20,6 +20,7 @@ import {
MAX_RULES_TO_UPDATE_IN_PARALLEL,
RULES_TABLE_MAX_PAGE_SIZE,
} from '../../../../../../../common/constants';
import type { PerformBulkActionResponse } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
import {
BulkActionType,
PerformBulkActionRequestBody,
@ -246,7 +247,7 @@ export const performBulkActionRoute = (
},
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<PerformBulkActionResponse>> => {
const { body } = request;
const siemResponse = buildSiemResponse(response);

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { Logger } from '@kbn/core/server';
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { validate } from '@kbn/securitysolution-io-ts-utils';
import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../../../common/constants';
@ -52,7 +52,7 @@ export const bulkCreateRulesRoute = (
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<BulkCrudRulesResponse>> => {
logDeprecatedBulkEndpoint(logger, DETECTION_ENGINE_RULES_BULK_CREATE);
const siemResponse = buildSiemResponse(response);

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { RouteConfig, RequestHandler, Logger } from '@kbn/core/server';
import type { RouteConfig, RequestHandler, Logger, IKibanaResponse } from '@kbn/core/server';
import { validate } from '@kbn/securitysolution-io-ts-utils';
import { DETECTION_ENGINE_RULES_BULK_DELETE } from '../../../../../../../common/constants';
@ -54,7 +54,11 @@ export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logge
tags: ['access:securitySolution'],
},
};
const handler: Handler = async (context, request, response) => {
const handler: Handler = async (
context,
request,
response
): Promise<IKibanaResponse<BulkCrudRulesResponse>> => {
logDeprecatedBulkEndpoint(logger, DETECTION_ENGINE_RULES_BULK_DELETE);
const siemResponse = buildSiemResponse(response);

View file

@ -6,7 +6,7 @@
*/
import { validate } from '@kbn/securitysolution-io-ts-utils';
import type { Logger } from '@kbn/core/server';
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../../../common/constants';
import {
@ -46,7 +46,7 @@ export const bulkPatchRulesRoute = (
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<BulkCrudRulesResponse>> => {
logDeprecatedBulkEndpoint(logger, DETECTION_ENGINE_RULES_BULK_UPDATE);
const siemResponse = buildSiemResponse(response);

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { Logger } from '@kbn/core/server';
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { validate } from '@kbn/securitysolution-io-ts-utils';
import {
@ -51,7 +51,7 @@ export const bulkUpdateRulesRoute = (
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<BulkCrudRulesResponse>> => {
logDeprecatedBulkEndpoint(logger, DETECTION_ENGINE_RULES_BULK_UPDATE);
const siemResponse = buildSiemResponse(response);

View file

@ -6,13 +6,15 @@
*/
import { transformError } from '@kbn/securitysolution-es-utils';
import type { IKibanaResponse } from '@kbn/core/server';
import type { CoverageOverviewResponse } from '../../../../../../../common/api/detection_engine';
import {
CoverageOverviewRequestBody,
RULE_MANAGEMENT_COVERAGE_OVERVIEW_URL,
} from '../../../../../../../common/api/detection_engine';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { buildSiemResponse } from '../../../../routes/utils';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../../routes/utils';
import { handleCoverageOverviewRequest } from './handle_coverage_overview_request';
export const getCoverageOverviewRoute = (router: SecuritySolutionPluginRouter) => {
@ -26,7 +28,7 @@ export const getCoverageOverviewRoute = (router: SecuritySolutionPluginRouter) =
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<CoverageOverviewResponse>> => {
const siemResponse = buildSiemResponse(response);
try {

View file

@ -6,20 +6,19 @@
*/
import { transformError } from '@kbn/securitysolution-es-utils';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import { validateCreateRuleProps } from '../../../../../../../common/api/detection_engine/rule_management';
import type { IKibanaResponse } from '@kbn/core/server';
import { RuleCreateProps } from '../../../../../../../common/api/detection_engine/model/rule_schema';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import type { CreateRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management';
import { validateCreateRuleProps } from '../../../../../../../common/api/detection_engine/rule_management';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { SetupPlugins } from '../../../../../../plugin';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildMlAuthz } from '../../../../../machine_learning/authz';
import { throwAuthzError } from '../../../../../machine_learning/validation';
import { readRules } from '../../../logic/crud/read_rules';
import { buildSiemResponse } from '../../../../routes/utils';
import { createRules } from '../../../logic/crud/create_rules';
import { readRules } from '../../../logic/crud/read_rules';
import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list';
import { validateRuleDefaultExceptionList } from '../../../logic/exceptions/validate_rule_default_exception_list';
import { transformValidate, validateResponseActionsPermissions } from '../../../utils/validate';
@ -38,7 +37,7 @@ export const createRuleRoute = (
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<CreateRuleResponse>> => {
const siemResponse = buildSiemResponse(response);
const validationErrors = validateCreateRuleProps(request.body);
if (validationErrors.length) {
@ -104,7 +103,7 @@ export const createRuleRoute = (
if (errors != null) {
return siemResponse.error({ statusCode: 500, body: errors });
} else {
return response.ok({ body: validated ?? {} });
return response.ok({ body: validated });
}
} catch (err) {
const error = transformError(err as Error);

View file

@ -7,7 +7,9 @@
import { transformError } from '@kbn/securitysolution-es-utils';
import type { IKibanaResponse } from '@kbn/core/server';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { DeleteRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management';
import {
QueryRuleByIds,
validateQueryRuleByIds,
@ -32,7 +34,7 @@ export const deleteRuleRoute = (router: SecuritySolutionPluginRouter) => {
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<DeleteRuleResponse>> => {
const siemResponse = buildSiemResponse(response);
const validationErrors = validateQueryRuleByIds(request.query);
if (validationErrors.length) {

View file

@ -9,7 +9,6 @@ import { transformError } from '@kbn/securitysolution-es-utils';
import type { Logger } from '@kbn/core/server';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { ExportRulesRequestQueryDecoded } from '../../../../../../../common/api/detection_engine/rule_management';
import {
ExportRulesRequestBody,
ExportRulesRequestQuery,
@ -32,9 +31,7 @@ export const exportRulesRoute = (
{
path: `${DETECTION_ENGINE_RULES_URL}/_export`,
validate: {
query: buildRouteValidation<typeof ExportRulesRequestQuery, ExportRulesRequestQueryDecoded>(
ExportRulesRequestQuery
),
query: buildRouteValidation(ExportRulesRequestQuery),
body: buildRouteValidation(ExportRulesRequestBody),
},
options: {

View file

@ -8,6 +8,7 @@
import { transformError } from '@kbn/securitysolution-es-utils';
import { validate } from '@kbn/securitysolution-io-ts-utils';
import type { RulesClient } from '@kbn/alerting-plugin/server';
import type { IKibanaResponse } from '@kbn/core/server';
import {
GetRuleManagementFiltersResponse,
RULE_MANAGEMENT_FILTERS_URL,
@ -59,7 +60,7 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) =
tags: ['access:securitySolution'],
},
},
async (context, _, response) => {
async (context, _, response): Promise<IKibanaResponse<GetRuleManagementFiltersResponse>> => {
const siemResponse = buildSiemResponse(response);
const ctx = await context.resolve(['alerting']);
const rulesClient = ctx.alerting.getRulesClient();
@ -84,7 +85,7 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) =
if (validationError != null) {
return siemResponse.error({ statusCode: 500, body: validationError });
} else {
return response.ok({ body: validatedBody ?? {} });
return response.ok({ body: validatedBody });
}
} catch (err) {
const error = transformError(err);

View file

@ -13,6 +13,7 @@ import { createPromiseFromStreams } from '@kbn/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import { validate } from '@kbn/securitysolution-io-ts-utils';
import type { IKibanaResponse } from '@kbn/core/server';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { ImportRulesRequestQueryDecoded } from '../../../../../../../common/api/detection_engine/rule_management';
import {
@ -63,7 +64,7 @@ export const importRulesRoute = (
},
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<ImportRulesResponse>> => {
const siemResponse = buildSiemResponse(response);
try {
@ -145,7 +146,7 @@ export const importRulesRoute = (
overwrite: request.query.overwrite_action_connectors,
});
// rulesWithMigratedActions: Is returened only in case connectors were exorted from different namesapce and the
// rulesWithMigratedActions: Is returned only in case connectors were exported from different namespace and the
// original rules actions' ids were replaced with new destinationIds
const parsedRules = actionConnectorErrors.length
? []

View file

@ -5,23 +5,22 @@
* 2.0.
*/
import type { IKibanaResponse } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { PatchRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management';
import {
PatchRuleRequestBody,
validatePatchRuleRequestBody,
} from '../../../../../../../common/api/detection_engine/rule_management';
import { buildRouteValidationNonExact } from '../../../../../../utils/build_validation/route_validation';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { SetupPlugins } from '../../../../../../plugin';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { buildRouteValidationNonExact } from '../../../../../../utils/build_validation/route_validation';
import { buildMlAuthz } from '../../../../../machine_learning/authz';
import { throwAuthzError } from '../../../../../machine_learning/validation';
import { buildSiemResponse } from '../../../../routes/utils';
import { readRules } from '../../../logic/crud/read_rules';
import { patchRules } from '../../../logic/crud/patch_rules';
import { readRules } from '../../../logic/crud/read_rules';
import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list';
import { validateRuleDefaultExceptionList } from '../../../logic/exceptions/validate_rule_default_exception_list';
import { getIdError } from '../../../utils/utils';
@ -41,7 +40,7 @@ export const patchRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupPl
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<PatchRuleResponse>> => {
const siemResponse = buildSiemResponse(response);
const validationErrors = validatePatchRuleRequestBody(request.body);
if (validationErrors.length) {

View file

@ -5,21 +5,19 @@
* 2.0.
*/
import type { Logger } from '@kbn/core/server';
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { ReadRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management';
import {
ReadRuleRequestQuery,
validateQueryRuleByIds,
} from '../../../../../../../common/api/detection_engine/rule_management';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../../routes/utils';
import { getIdError, transform } from '../../../utils/utils';
import { readRules } from '../../../logic/crud/read_rules';
import { getIdError, transform } from '../../../utils/utils';
export const readRuleRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
router.get(
@ -32,7 +30,7 @@ export const readRuleRoute = (router: SecuritySolutionPluginRouter, logger: Logg
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<ReadRuleResponse>> => {
const siemResponse = buildSiemResponse(response);
const validationErrors = validateQueryRuleByIds(request.query);
if (validationErrors.length) {

View file

@ -5,25 +5,24 @@
* 2.0.
*/
import type { IKibanaResponse } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import { validateUpdateRuleProps } from '../../../../../../../common/api/detection_engine/rule_management';
import { RuleUpdateProps } from '../../../../../../../common/api/detection_engine/model/rule_schema';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import type { UpdateRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management';
import { validateUpdateRuleProps } from '../../../../../../../common/api/detection_engine/rule_management';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants';
import type { SetupPlugins } from '../../../../../../plugin';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildMlAuthz } from '../../../../../machine_learning/authz';
import { throwAuthzError } from '../../../../../machine_learning/validation';
import { buildSiemResponse } from '../../../../routes/utils';
import { getIdError } from '../../../utils/utils';
import { transformValidate, validateResponseActionsPermissions } from '../../../utils/validate';
import { updateRules } from '../../../logic/crud/update_rules';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { readRules } from '../../../logic/crud/read_rules';
import { updateRules } from '../../../logic/crud/update_rules';
import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list';
import { validateRuleDefaultExceptionList } from '../../../logic/exceptions/validate_rule_default_exception_list';
import { getIdError } from '../../../utils/utils';
import { transformValidate, validateResponseActionsPermissions } from '../../../utils/validate';
export const updateRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => {
router.put(
@ -36,7 +35,7 @@ export const updateRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupP
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<UpdateRuleResponse>> => {
const siemResponse = buildSiemResponse(response);
const validationErrors = validateUpdateRuleProps(request.body);
if (validationErrors.length) {

View file

@ -5,12 +5,12 @@
* 2.0.
*/
import { transformError } from '@kbn/securitysolution-es-utils';
import type { IKibanaResponse } from '@kbn/core/server';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { transformError } from '@kbn/securitysolution-es-utils';
import type { ReadTagsResponse } from '../../../../../../../common/api/detection_engine';
import { DETECTION_ENGINE_TAGS_URL } from '../../../../../../../common/constants';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { buildSiemResponse } from '../../../../routes/utils';
import { readTags } from './read_tags';
export const readTagsRoute = (router: SecuritySolutionPluginRouter) => {
@ -22,7 +22,7 @@ export const readTagsRoute = (router: SecuritySolutionPluginRouter) => {
tags: ['access:securitySolution'],
},
},
async (context, request, response): Promise<IKibanaResponse<string[]>> => {
async (context, request, response): Promise<IKibanaResponse<ReadTagsResponse>> => {
const siemResponse = buildSiemResponse(response);
const rulesClient = (await context.alerting)?.getRulesClient();

View file

@ -36,7 +36,7 @@ import type {
export const transformValidate = (
rule: PartialRule<RuleParams>
): [RuleResponse | null, string | null] => {
): [RuleResponse, null] | [null, string] => {
const transformed = transform(rule);
if (transformed == null) {
return [null, 'Internal error transforming'];

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { KibanaResponseFactory } from '@kbn/core-http-server';
import type { IKibanaResponse, KibanaResponseFactory } from '@kbn/core-http-server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../../routes/utils';
@ -65,7 +65,7 @@ export const getClusterHealthRoute = (router: SecuritySolutionPluginRouter) => {
access: 'public', // must be public to enable "system" users to collect data
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<GetClusterHealthResponse>> => {
return handleClusterHealthRequest({
response,
resolveParameters: () => validateGetClusterHealthRequest(request.body),

View file

@ -6,6 +6,7 @@
*/
import { transformError } from '@kbn/securitysolution-es-utils';
import type { IKibanaResponse } from '@kbn/core/server';
import type { GetRuleHealthResponse } from '../../../../../../../common/api/detection_engine/rule_monitoring';
import {
@ -39,7 +40,7 @@ export const getRuleHealthRoute = (router: SecuritySolutionPluginRouter) => {
access: 'public', // must be public to enable "system" users to collect data
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<GetRuleHealthResponse>> => {
const siemResponse = buildSiemResponse(response);
try {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { KibanaResponseFactory } from '@kbn/core-http-server';
import type { IKibanaResponse, KibanaResponseFactory } from '@kbn/core-http-server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../../routes/utils';
@ -41,7 +41,7 @@ export const getSpaceHealthRoute = (router: SecuritySolutionPluginRouter) => {
access: 'public', // must be public to enable "system" users to collect data
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<GetSpaceHealthResponse>> => {
return handleSpaceHealthRequest({
response,
resolveParameters: () => validateGetSpaceHealthRequest({}),

View file

@ -5,11 +5,12 @@
* 2.0.
*/
import type { IKibanaResponse } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { buildSiemResponse } from '../../../../routes/utils';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { SETUP_HEALTH_URL } from '../../../../../../../common/api/detection_engine/rule_monitoring';
import type { SetupHealthResponse } from '../../../../../../../common/api/detection_engine';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { buildSiemResponse } from '../../../../routes/utils';
/**
* Similar to the "setup" command of beats, this endpoint installs resources
@ -26,7 +27,7 @@ export const setupHealthRoute = (router: SecuritySolutionPluginRouter) => {
access: 'public', // must be public to enable "system" users to collect data
},
},
async (context, request, response) => {
async (context, request, response): Promise<IKibanaResponse<SetupHealthResponse>> => {
const siemResponse = buildSiemResponse(response);
try {

View file

@ -6,6 +6,7 @@
*/
import { transformError } from '@kbn/securitysolution-es-utils';
import type { IKibanaResponse } from '@kbn/core/server';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../../routes/utils';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
@ -33,7 +34,11 @@ export const getRuleExecutionEventsRoute = (router: SecuritySolutionPluginRouter
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (
context,
request,
response
): Promise<IKibanaResponse<GetRuleExecutionEventsResponse>> => {
const { params, query } = request;
const siemResponse = buildSiemResponse(response);
@ -49,9 +54,7 @@ export const getRuleExecutionEventsRoute = (router: SecuritySolutionPluginRouter
perPage: query.per_page,
});
const responseBody: GetRuleExecutionEventsResponse = executionEventsResponse;
return response.ok({ body: responseBody });
return response.ok({ body: executionEventsResponse });
} catch (err) {
const error = transformError(err);
return siemResponse.error({

View file

@ -6,6 +6,7 @@
*/
import { transformError } from '@kbn/securitysolution-es-utils';
import type { IKibanaResponse } from '@kbn/core/server';
import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../../routes/utils';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
@ -33,7 +34,11 @@ export const getRuleExecutionResultsRoute = (router: SecuritySolutionPluginRoute
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
async (
context,
request,
response
): Promise<IKibanaResponse<GetRuleExecutionResultsResponse>> => {
const { ruleId } = request.params;
const {
start,
@ -63,9 +68,7 @@ export const getRuleExecutionResultsRoute = (router: SecuritySolutionPluginRoute
sortOrder,
});
const responseBody: GetRuleExecutionResultsResponse = executionResultsResponse;
return response.ok({ body: responseBody });
return response.ok({ body: executionResultsResponse });
} catch (err) {
const error = transformError(err);
return siemResponse.error({