Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution] Show deprecated bulk endpoints in Upgrade Assistant #207091

Merged
Merged
36 changes: 36 additions & 0 deletions docs/upgrade-notes.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,42 @@ For Elastic Security solution release information, refer to {security-guide}/rel
[float]
=== Breaking changes

[discrete]
[[breaking-207091]]
.Removed legacy security rules bulk endpoints (9.0.0)
[%collapsible]
====
*Details* +
--
* `POST /api/detection_engine/rules/_bulk_create` has been replaced by `POST /api/detection_engine/rules/_import`
* `PUT /api/detection_engine/rules/_bulk_update` has been replaced by `POST /api/detection_engine/rules/_bulk_action`
* `PATCH /api/detection_engine/rules/_bulk_update has been replaced by `POST /api/detection_engine/rules/_bulk_action`
* `DELETE /api/detection_engine/rules/_bulk_delete` has been replaced by `POST /api/detection_engine/rules/_bulk_action`
* `POST api/detection_engine/rules/_bulk_delete` has been replaced by `POST /api/detection_engine/rules/_bulk_action`
--
These changes were introduced in {kibana-pull}197422[#197422].

*Impact* +
Deprecated endpoints will fail with a 404 status code starting from version 9.0.0

*Action* +
--
Update your implementations to use the new endpoints:

* **For bulk creation of rules:**
- Use `POST /api/detection_engine/rules/_import` (link:{api-kibana}/operation/operation-importrules[API documentation]) to create multiple rules along with their associated entities (for example, exceptions and action connectors).
- Alternatively, create rules individually using `POST /api/detection_engine/rules` (link:{api-kibana}/operation/operation-createrule[API documentation]).

* **For bulk updates of rules:**
- Use `POST /api/detection_engine/rules/_bulk_action` (link:{api-kibana}/operation/operation-performrulesbulkaction[API documentation]) to update fields in multiple rules simultaneously.
- Alternatively, update rules individually using `PUT /api/detection_engine/rules` (link:{api-kibana}/operation/operation-updaterule[API documentation]).

* **For bulk deletion of rules:**
- Use `POST /api/detection_engine/rules/_bulk_action` (link:{api-kibana}/operation/operation-performrulesbulkaction[API documentation]) to delete multiple rules by IDs or query.
- Alternatively, delete rules individually using `DELETE /api/detection_engine/rules` (link:{api-kibana}/operation/operation-deleterule[API documentation]).
--
====

[discrete]
[[breaking-199598]]
.Remove deprecated endpoint management endpoints (9.0.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
aiAssistant: `${SECURITY_SOLUTION_DOCS}security-assistant.html`,
signalsMigrationApi: `${SECURITY_SOLUTION_DOCS}signals-migration-api.html`,
legacyEndpointManagementApiDeprecations: `${KIBANA_DOCS}breaking-changes-summary.html#breaking-199598`,
legacyBulkApiDeprecations: `${KIBANA_DOCS}breaking-changes-summary.html#breaking-207091`,
},
query: {
eql: `${ELASTICSEARCH_DOCS}eql.html`,
Expand Down
1 change: 1 addition & 0 deletions src/platform/packages/shared/kbn-doc-links/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ export interface DocLinks {
readonly detectionEngineOverview: string;
readonly signalsMigrationApi: string;
readonly legacyEndpointManagementApiDeprecations: string;
readonly legacyBulkApiDeprecations: string;
};
readonly query: {
readonly eql: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ export const DETECTION_ENGINE_RULES_BULK_CREATE =
`${DETECTION_ENGINE_RULES_URL}/_bulk_create` as const;
export const DETECTION_ENGINE_RULES_BULK_UPDATE =
`${DETECTION_ENGINE_RULES_URL}/_bulk_update` as const;
export const DETECTION_ENGINE_RULES_IMPORT_URL = `${DETECTION_ENGINE_RULES_URL}/_import` as const;

export * from './entity_analytics/constants';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
import type { BulkActionsDryRunErrCode } from '../../../../common/constants';
import {
DETECTION_ENGINE_RULES_BULK_ACTION,
DETECTION_ENGINE_RULES_IMPORT_URL,
DETECTION_ENGINE_RULES_PREVIEW,
DETECTION_ENGINE_RULES_URL,
DETECTION_ENGINE_RULES_URL_FIND,
Expand Down Expand Up @@ -455,21 +456,18 @@ export const importRules = async ({
const formData = new FormData();
formData.append('file', fileToImport);

return KibanaServices.get().http.fetch<ImportDataResponse>(
`${DETECTION_ENGINE_RULES_URL}/_import`,
{
method: 'POST',
version: '2023-10-31',
headers: { 'Content-Type': undefined },
query: {
overwrite,
overwrite_exceptions: overwriteExceptions,
overwrite_action_connectors: overwriteActionConnectors,
},
body: formData,
signal,
}
);
return KibanaServices.get().http.fetch<ImportDataResponse>(DETECTION_ENGINE_RULES_IMPORT_URL, {
method: 'POST',
version: '2023-10-31',
headers: { 'Content-Type': undefined },
query: {
overwrite,
overwrite_exceptions: overwriteExceptions,
overwrite_action_connectors: overwriteActionConnectors,
},
body: formData,
signal,
});
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
DETECTION_ENGINE_RULES_BULK_DELETE,
DETECTION_ENGINE_RULES_BULK_CREATE,
DETECTION_ENGINE_RULES_URL_FIND,
DETECTION_ENGINE_RULES_IMPORT_URL,
} from '../../../../../common/constants';
import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/api/detection_engine/rule_management/urls';

Expand Down Expand Up @@ -260,14 +261,14 @@ export const getFindResultWithMultiHits = ({
export const getImportRulesRequest = (hapiStream?: HapiReadableStream) =>
requestMock.create({
method: 'post',
path: `${DETECTION_ENGINE_RULES_URL}/_import`,
path: DETECTION_ENGINE_RULES_IMPORT_URL,
body: { file: hapiStream },
});

export const getImportRulesRequestOverwriteTrue = (hapiStream?: HapiReadableStream) =>
requestMock.create({
method: 'post',
path: `${DETECTION_ENGINE_RULES_URL}/_import`,
path: DETECTION_ENGINE_RULES_IMPORT_URL,
body: { file: hapiStream },
query: { overwrite: true },
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import type { DocLinksServiceSetup, Logger } from '@kbn/core/server';
import type { ConfigType } from '../../../../config';
import type { SetupPlugins } from '../../../../plugin_contract';
import type { SecuritySolutionPluginRouter } from '../../../../types';
Expand All @@ -22,12 +22,17 @@ import { readRuleRoute } from './rules/read_rule/route';
import { updateRuleRoute } from './rules/update_rule/route';
import { readTagsRoute } from './tags/read_tags/route';
import { getCoverageOverviewRoute } from './rules/coverage_overview/route';
import { bulkCreateRulesRoute } from './rules/bulk_create_rules/route';
import { bulkUpdateRulesRoute } from './rules/bulk_update_rules/route';
import { bulkPatchRulesRoute } from './rules/bulk_patch_rules/route';
import { bulkDeleteRulesRoute } from './rules/bulk_delete_rules/route';

export const registerRuleManagementRoutes = (
router: SecuritySolutionPluginRouter,
config: ConfigType,
ml: SetupPlugins['ml'],
logger: Logger
logger: Logger,
docLinks: DocLinksServiceSetup
) => {
// Rules CRUD
createRuleRoute(router);
Expand All @@ -36,6 +41,12 @@ export const registerRuleManagementRoutes = (
patchRuleRoute(router);
deleteRuleRoute(router);

// These four bulk endpoints are deprecated and will be removed in 9.0
bulkCreateRulesRoute(router, logger, docLinks);
bulkUpdateRulesRoute(router, logger, docLinks);
bulkPatchRulesRoute(router, logger, docLinks);
bulkDeleteRulesRoute(router, logger, docLinks);

// Rules bulk actions
performBulkActionRoute(router, config, ml, logger);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { bulkCreateRulesRoute } from './route';
import { getCreateRulesSchemaMock } from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks';
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
import { getQueryRuleParams } from '../../../../rule_schema/mocks';
import { loggingSystemMock } from '@kbn/core/server/mocks';
import { loggingSystemMock, docLinksServiceMock } from '@kbn/core/server/mocks';
import { HttpAuthzError } from '../../../../../machine_learning/validation';
import { getRulesSchemaMock } from '../../../../../../../common/api/detection_engine/model/rule_schema/rule_response_schema.mock';

Expand All @@ -32,14 +32,15 @@ describe('Bulk create rules route', () => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());
const logger = loggingSystemMock.createLogger();
const docLinks = docLinksServiceMock.createSetupContract();

clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); // no existing rules
clients.rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams())); // successful creation
clients.detectionRulesClient.createCustomRule.mockResolvedValue(getRulesSchemaMock());
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue(
elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse())
);
bulkCreateRulesRoute(server.router, logger);
bulkCreateRulesRoute(server.router, logger, docLinks);
});

describe('status codes', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
* 2.0.
*/

import type { IKibanaResponse, Logger } from '@kbn/core/server';
import type { DocLinksServiceSetup, IKibanaResponse, Logger } from '@kbn/core/server';

import { transformError } from '@kbn/securitysolution-es-utils';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../../../common/constants';
import {
DETECTION_ENGINE_RULES_BULK_CREATE,
DETECTION_ENGINE_RULES_IMPORT_URL,
} from '../../../../../../../common/constants';
import {
BulkCreateRulesRequestBody,
validateCreateRuleProps,
Expand All @@ -34,7 +37,11 @@ import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from '../.
*
* TODO: https://github.com/elastic/kibana/issues/193184 Delete this route and clean up the code
*/
export const bulkCreateRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
export const bulkCreateRulesRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger,
docLinks: DocLinksServiceSetup
) => {
router.versioned
.post({
access: 'public',
Expand All @@ -58,6 +65,17 @@ export const bulkCreateRulesRoute = (router: SecuritySolutionPluginRouter, logge
body: buildRouteValidationWithZod(BulkCreateRulesRequestBody),
},
},
options: {
deprecated: {
documentationUrl: docLinks.links.securitySolution.legacyBulkApiDeprecations,
severity: 'critical',
reason: {
type: 'migrate',
newApiMethod: 'POST',
newApiPath: DETECTION_ENGINE_RULES_IMPORT_URL,
},
},
},
},
async (context, request, response): Promise<IKibanaResponse<BulkCrudRulesResponse>> => {
logDeprecatedBulkEndpoint(logger, DETECTION_ENGINE_RULES_BULK_CREATE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '../../../../routes/__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__';
import { bulkDeleteRulesRoute } from './route';
import { loggingSystemMock } from '@kbn/core/server/mocks';
import { loggingSystemMock, docLinksServiceMock } from '@kbn/core/server/mocks';

describe('Bulk delete rules route', () => {
let server: ReturnType<typeof serverMock.create>;
Expand All @@ -27,12 +27,13 @@ describe('Bulk delete rules route', () => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());
const logger = loggingSystemMock.createLogger();
const docLinks = docLinksServiceMock.createSetupContract();

clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // rule exists
clients.rulesClient.delete.mockResolvedValue({}); // successful deletion
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); // rule status request

bulkDeleteRulesRoute(server.router, logger);
bulkDeleteRulesRoute(server.router, logger, docLinks);
});

describe('status codes with actionClient and alertClient', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
*/

import type { VersionedRouteConfig } from '@kbn/core-http-server';
import type { IKibanaResponse, Logger, RequestHandler } from '@kbn/core/server';
import type {
DocLinksServiceSetup,
IKibanaResponse,
Logger,
RequestHandler,
} from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import type {
Expand All @@ -19,7 +24,10 @@ import {
BulkDeleteRulesRequestBody,
validateQueryRuleByIds,
} from '../../../../../../../common/api/detection_engine/rule_management';
import { DETECTION_ENGINE_RULES_BULK_DELETE } from '../../../../../../../common/constants';
import {
DETECTION_ENGINE_RULES_BULK_ACTION,
DETECTION_ENGINE_RULES_BULK_DELETE,
} from '../../../../../../../common/constants';
import type {
SecuritySolutionPluginRouter,
SecuritySolutionRequestHandlerContext,
Expand Down Expand Up @@ -48,7 +56,11 @@ type Handler = RequestHandler<
*
* TODO: https://github.com/elastic/kibana/issues/193184 Delete this route and clean up the code
*/
export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
export const bulkDeleteRulesRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger,
docLinks: DocLinksServiceSetup
) => {
const handler: Handler = async (
context,
request,
Expand Down Expand Up @@ -126,6 +138,17 @@ export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logge
body: buildRouteValidationWithZod(BulkDeleteRulesRequestBody),
},
},
options: {
deprecated: {
documentationUrl: docLinks.links.securitySolution.legacyBulkApiDeprecations,
severity: 'critical',
reason: {
type: 'migrate',
newApiMethod: 'POST',
newApiPath: DETECTION_ENGINE_RULES_BULK_ACTION,
},
},
},
},
handler
);
Expand All @@ -137,6 +160,17 @@ export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logge
body: buildRouteValidationWithZod(BulkDeleteRulesPostRequestBody),
},
},
options: {
deprecated: {
documentationUrl: docLinks.links.securitySolution.legacyBulkApiDeprecations,
severity: 'critical',
reason: {
type: 'migrate',
newApiMethod: 'POST',
newApiPath: DETECTION_ENGINE_RULES_BULK_ACTION,
},
},
},
},
handler
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
import { bulkPatchRulesRoute } from './route';
import { getCreateRulesSchemaMock } from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks';
import { getMlRuleParams, getQueryRuleParams } from '../../../../rule_schema/mocks';
import { loggingSystemMock } from '@kbn/core/server/mocks';
import { loggingSystemMock, docLinksServiceMock } from '@kbn/core/server/mocks';
import { HttpAuthzError } from '../../../../../machine_learning/validation';

describe('Bulk patch rules route', () => {
Expand All @@ -35,12 +35,13 @@ describe('Bulk patch rules route', () => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());
const logger = loggingSystemMock.createLogger();
const docLinks = docLinksServiceMock.createSetupContract();

clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); // rule exists
clients.rulesClient.update.mockResolvedValue(getRuleMock(getQueryRuleParams())); // update succeeds
clients.detectionRulesClient.patchRule.mockResolvedValue(getRulesSchemaMock());

bulkPatchRulesRoute(server.router, logger);
bulkPatchRulesRoute(server.router, logger, docLinks);
});

describe('status codes', () => {
Expand Down
Loading
Loading