Skip to content

Commit

Permalink
[ResponseOps][Cases] Make deprecated APIs internal in serverless (ela…
Browse files Browse the repository at this point in the history
…stic#198378)

## Summary
 
Fixes: elastic#198407

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### For maintainers

- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels)
  • Loading branch information
cnasikas authored Nov 1, 2024
1 parent f5d9f0d commit 2ae6333
Show file tree
Hide file tree
Showing 18 changed files with 481 additions and 169 deletions.
7 changes: 6 additions & 1 deletion x-pack/plugins/cases/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,14 @@ export class CasePlugin
const router = core.http.createRouter<CasesRequestHandlerContext>();
const telemetryUsageCounter = plugins.usageCollection?.createUsageCounter(APP_ID);

const isServerless = plugins.cloud?.isServerlessEnabled;

registerRoutes({
router,
routes: [...getExternalRoutes(), ...getInternalRoutes(this.userProfileService)],
routes: [
...getExternalRoutes({ isServerless }),
...getInternalRoutes(this.userProfileService),
],
logger: this.logger,
kibanaVersion: this.kibanaVersion,
telemetryUsageCounter,
Expand Down
62 changes: 62 additions & 0 deletions x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 { createCasesClientMock } from '../../../client/mocks';
import { getCaseRoute } from './get_case';
import { httpServerMock, loggingSystemMock } from '@kbn/core/server/mocks';

describe('getCaseRoute', () => {
const casesClientMock = createCasesClientMock();
const logger = loggingSystemMock.createLogger();
const response = httpServerMock.createResponseFactory();
const kibanaVersion = '8.17';
const context = { cases: { getCasesClient: jest.fn().mockResolvedValue(casesClientMock) } };

it('throws a bad request if the includeComments is set in serverless', async () => {
const router = getCaseRoute({ isServerless: true });
const request = httpServerMock.createKibanaRequest({
path: '/api/cases/{case_id}/?includeComments=true',
query: { includeComments: true },
params: { case_id: 'foo' },
});

await expect(
// @ts-expect-error: no need to create the context
router.handler({ response, request, logger, kibanaVersion, context })
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Failed to retrieve case in route case id: foo
include comments: true: Error: includeComments is not supported"
`);
});

it('does not throw a bad request if the includeComments is set in non-serverless', async () => {
const router = getCaseRoute({ isServerless: false });
const request = httpServerMock.createKibanaRequest({
path: '/api/cases/{case_id}/?includeComments=true',
query: { includeComments: true },
params: { case_id: 'foo' },
});

await expect(
// @ts-expect-error: no need to create the context
router.handler({ response, request, logger, kibanaVersion, context })
).resolves.not.toThrow();
});

it('does not throw a bad request if the includeComments is not set in serverless', async () => {
const router = getCaseRoute({ isServerless: true });
const request = httpServerMock.createKibanaRequest({
path: '/api/cases/{case_id}',
params: { case_id: 'foo' },
});

await expect(
// @ts-expect-error: no need to create the context
router.handler({ response, request, logger, kibanaVersion, context })
).resolves.not.toThrow();
});
});
92 changes: 49 additions & 43 deletions x-pack/plugins/cases/server/routes/api/cases/get_case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import Boom from '@hapi/boom';
import { schema } from '@kbn/config-schema';

import type { caseApiV1 } from '../../../../common/types/api';
Expand All @@ -26,53 +27,58 @@ const params = {
}),
};

export const getCaseRoute = createCasesRoute({
method: 'get',
path: CASE_DETAILS_URL,
params,
routerOptions: {
access: 'public',
summary: `Get a case`,
tags: ['oas-tag:cases'],
},
handler: async ({ context, request, response, logger, kibanaVersion }) => {
try {
const isIncludeCommentsParamProvidedByTheUser =
request.url.searchParams.has('includeComments');
export const getCaseRoute = ({ isServerless }: { isServerless?: boolean }) =>
createCasesRoute({
method: 'get',
path: CASE_DETAILS_URL,
params,
routerOptions: {
access: 'public',
summary: `Get a case`,
tags: ['oas-tag:cases'],
},
handler: async ({ context, request, response, logger, kibanaVersion }) => {
try {
const isIncludeCommentsParamProvidedByTheUser =
request.url.searchParams.has('includeComments');

if (isIncludeCommentsParamProvidedByTheUser) {
logDeprecatedEndpoint(
logger,
request.headers,
`The query parameter 'includeComments' of the get case API '${CASE_DETAILS_URL}' is deprecated`
);
}
if (isServerless && isIncludeCommentsParamProvidedByTheUser) {
throw Boom.badRequest('includeComments is not supported');
}

const caseContext = await context.cases;
const casesClient = await caseContext.getCasesClient();
const id = request.params.case_id;
if (isIncludeCommentsParamProvidedByTheUser) {
logDeprecatedEndpoint(
logger,
request.headers,
`The query parameter 'includeComments' of the get case API '${CASE_DETAILS_URL}' is deprecated`
);
}

const res: caseDomainV1.Case = await casesClient.cases.get({
id,
includeComments: request.query.includeComments,
});
const caseContext = await context.cases;
const casesClient = await caseContext.getCasesClient();
const id = request.params.case_id;

return response.ok({
...(isIncludeCommentsParamProvidedByTheUser && {
headers: {
...getWarningHeader(kibanaVersion, 'Deprecated query parameter includeComments'),
},
}),
body: res,
});
} catch (error) {
throw createCaseError({
message: `Failed to retrieve case in route case id: ${request.params.case_id} \ninclude comments: ${request.query.includeComments}: ${error}`,
error,
});
}
},
});
const res: caseDomainV1.Case = await casesClient.cases.get({
id,
includeComments: request.query.includeComments,
});

return response.ok({
...(isIncludeCommentsParamProvidedByTheUser && {
headers: {
...getWarningHeader(kibanaVersion, 'Deprecated query parameter includeComments'),
},
}),
body: res,
});
} catch (error) {
throw createCaseError({
message: `Failed to retrieve case in route case id: ${request.params.case_id} \ninclude comments: ${request.query.includeComments}: ${error}`,
error,
});
}
},
});

export const resolveCaseRoute = createCasesRoute({
method: 'get',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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 { getAllCommentsRoute } from './get_all_comment';

describe('getAllCommentsRoute', () => {
it('marks the endpoint internal in serverless', async () => {
const router = getAllCommentsRoute({ isServerless: true });

expect(router.routerOptions?.access).toBe('internal');
});

it('marks the endpoint public in non-serverless', async () => {
const router = getAllCommentsRoute({ isServerless: false });

expect(router.routerOptions?.access).toBe('public');
});
});
75 changes: 38 additions & 37 deletions x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,42 @@ import type { attachmentDomainV1 } from '../../../../common/types/domain';
/**
* @deprecated since version 8.1.0
*/
export const getAllCommentsRoute = createCasesRoute({
method: 'get',
path: CASE_COMMENTS_URL,
params: {
params: schema.object({
case_id: schema.string(),
}),
},
options: {
deprecated: true,
},
routerOptions: {
access: 'public',
summary: `Gets all case comments`,
tags: ['oas-tag:cases'],
// description: 'You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases with the comments you\'re seeking.',
// @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo}
deprecated: true,
},
handler: async ({ context, request, response }) => {
try {
const caseContext = await context.cases;
const client = await caseContext.getCasesClient();
const res: attachmentDomainV1.Attachments = await client.attachments.getAll({
caseID: request.params.case_id,
});
export const getAllCommentsRoute = ({ isServerless }: { isServerless?: boolean }) =>
createCasesRoute({
method: 'get',
path: CASE_COMMENTS_URL,
params: {
params: schema.object({
case_id: schema.string(),
}),
},
options: {
deprecated: true,
},
routerOptions: {
access: isServerless ? 'internal' : 'public',
summary: `Gets all case comments`,
tags: ['oas-tag:cases'],
// description: 'You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases with the comments you\'re seeking.',
// @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo}
deprecated: true,
},
handler: async ({ context, request, response }) => {
try {
const caseContext = await context.cases;
const client = await caseContext.getCasesClient();
const res: attachmentDomainV1.Attachments = await client.attachments.getAll({
caseID: request.params.case_id,
});

return response.ok({
body: res,
});
} catch (error) {
throw createCaseError({
message: `Failed to get all comments in route case id: ${request.params.case_id}: ${error}`,
error,
});
}
},
});
return response.ok({
body: res,
});
} catch (error) {
throw createCaseError({
message: `Failed to get all comments in route case id: ${request.params.case_id}: ${error}`,
error,
});
}
},
});
10 changes: 5 additions & 5 deletions x-pack/plugins/cases/server/routes/api/get_external_routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,26 @@ import { postCaseConfigureRoute } from './configure/post_configure';
import { getAllAlertsAttachedToCaseRoute } from './comments/get_alerts';
import { findUserActionsRoute } from './user_actions/find_user_actions';

export const getExternalRoutes = () =>
export const getExternalRoutes = ({ isServerless }: { isServerless?: boolean }) =>
[
deleteCaseRoute,
findCaseRoute,
getCaseRoute,
getCaseRoute({ isServerless }),
resolveCaseRoute,
patchCaseRoute,
postCaseRoute,
pushCaseRoute,
findUserActionsRoute,
getUserActionsRoute,
getStatusRoute,
getUserActionsRoute({ isServerless }),
getStatusRoute({ isServerless }),
getCasesByAlertIdRoute,
getReportersRoute,
getTagsRoute,
deleteCommentRoute,
deleteAllCommentsRoute,
findCommentsRoute,
getCommentRoute,
getAllCommentsRoute,
getAllCommentsRoute({ isServerless }),
patchCommentRoute,
postCommentRoute,
getCaseConfigureRoute,
Expand Down
22 changes: 22 additions & 0 deletions x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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 { getStatusRoute } from './get_status';

describe('getStatusRoute', () => {
it('marks the endpoint internal in serverless', async () => {
const router = getStatusRoute({ isServerless: true });

expect(router.routerOptions?.access).toBe('internal');
});

it('marks the endpoint public in non-serverless', async () => {
const router = getStatusRoute({ isServerless: false });

expect(router.routerOptions?.access).toBe('public');
});
});
Loading

0 comments on commit 2ae6333

Please sign in to comment.