diff --git a/docs/api-generated/cases/case-apis-passthru.asciidoc b/docs/api-generated/cases/case-apis-passthru.asciidoc index d0e7a67c5066..f007882af237 100644 --- a/docs/api-generated/cases/case-apis-passthru.asciidoc +++ b/docs/api-generated/cases/case-apis-passthru.asciidoc @@ -556,7 +556,7 @@ Any modifications made to this file will be overwritten.
Query Parameter — The page number to return. default: 1
perPage (optional)
-
Query Parameter — The number of items to return. default: 20
sortOrder (optional)
+
Query Parameter — The number of items to return. Limited to 100 items. default: 20
sortOrder (optional)
Query Parameter — Determines the sort order. default: desc
diff --git a/x-pack/plugins/cases/common/constants/index.ts b/x-pack/plugins/cases/common/constants/index.ts index 33473a9c80bf..1a49de004e73 100644 --- a/x-pack/plugins/cases/common/constants/index.ts +++ b/x-pack/plugins/cases/common/constants/index.ts @@ -104,6 +104,7 @@ export const MAX_DOCS_PER_PAGE = 10000 as const; export const MAX_BULK_GET_ATTACHMENTS = MAX_DOCS_PER_PAGE; export const MAX_CONCURRENT_SEARCHES = 10 as const; export const MAX_BULK_GET_CASES = 1000 as const; +export const MAX_COMMENTS_PER_PAGE = 100 as const; export const MAX_CATEGORY_FILTER_LENGTH = 100 as const; /** diff --git a/x-pack/plugins/cases/docs/openapi/bundled.json b/x-pack/plugins/cases/docs/openapi/bundled.json index 92dcfe577930..78ba5444f40a 100644 --- a/x-pack/plugins/cases/docs/openapi/bundled.json +++ b/x-pack/plugins/cases/docs/openapi/bundled.json @@ -1852,7 +1852,15 @@ "$ref": "#/components/parameters/page_index" }, { - "$ref": "#/components/parameters/page_size" + "name": "perPage", + "in": "query", + "description": "The number of items to return. Limited to 100 items.", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } }, { "$ref": "#/components/parameters/sort_order" diff --git a/x-pack/plugins/cases/docs/openapi/bundled.yaml b/x-pack/plugins/cases/docs/openapi/bundled.yaml index 3d53916c89df..405cf4fb689f 100644 --- a/x-pack/plugins/cases/docs/openapi/bundled.yaml +++ b/x-pack/plugins/cases/docs/openapi/bundled.yaml @@ -1156,7 +1156,14 @@ paths: parameters: - $ref: '#/components/parameters/case_id' - $ref: '#/components/parameters/page_index' - - $ref: '#/components/parameters/page_size' + - name: perPage + in: query + description: The number of items to return. Limited to 100 items. + required: false + schema: + type: integer + default: 20 + maximum: 100 - $ref: '#/components/parameters/sort_order' - $ref: '#/components/parameters/space_id' responses: diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments@_find.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments@_find.yaml index b1dd32a65951..bb43f4dcc0b2 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments@_find.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments@_find.yaml @@ -10,7 +10,14 @@ get: parameters: - $ref: '../components/parameters/case_id.yaml' - $ref: '../components/parameters/page_index.yaml' - - $ref: '../components/parameters/page_size.yaml' + - name: perPage + in: query + description: The number of items to return. Limited to 100 items. + required: false + schema: + type: integer + default: 20 + maximum: 100 - $ref: '../components/parameters/sort_order.yaml' - $ref: '../components/parameters/space_id.yaml' responses: diff --git a/x-pack/plugins/cases/server/client/attachments/get.test.ts b/x-pack/plugins/cases/server/client/attachments/get.test.ts index 250cfa9f0b25..c2c3423b2388 100644 --- a/x-pack/plugins/cases/server/client/attachments/get.test.ts +++ b/x-pack/plugins/cases/server/client/attachments/get.test.ts @@ -18,12 +18,20 @@ describe('get', () => { it('Invalid total items results in error', async () => { await expect(() => - findComment({ caseID: 'mock-id', findQueryParams: { page: 2, perPage: 9001 } }, clientArgs) + findComment({ caseID: 'mock-id', findQueryParams: { page: 209, perPage: 100 } }, clientArgs) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Failed to find comments case id: mock-id: Error: The number of documents is too high. Paginating through more than 10,000 documents is not possible."` ); }); + it('Invalid perPage items results in error', async () => { + await expect(() => + findComment({ caseID: 'mock-id', findQueryParams: { page: 2, perPage: 9001 } }, clientArgs) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Failed to find comments case id: mock-id: Error: The provided perPage value was too high. The maximum allowed perPage value is 100."` + ); + }); + it('throws with excess fields', async () => { await expect( findComment( diff --git a/x-pack/plugins/cases/server/client/attachments/validators.test.ts b/x-pack/plugins/cases/server/client/attachments/validators.test.ts index 4626fd13fba3..ce6c43a665a1 100644 --- a/x-pack/plugins/cases/server/client/attachments/validators.test.ts +++ b/x-pack/plugins/cases/server/client/attachments/validators.test.ts @@ -6,10 +6,13 @@ */ import { validateFindCommentsPagination } from './validators'; +import { MAX_COMMENTS_PER_PAGE } from '../../../common/constants'; const ERROR_MSG = 'The number of documents is too high. Paginating through more than 10,000 documents is not possible.'; +const ERROR_MSG_PER_PAGE = `The provided perPage value was too high. The maximum allowed perPage value is ${MAX_COMMENTS_PER_PAGE}.`; + describe('validators', () => { describe('validateFindCommentsPagination', () => { it('does not throw if only page is undefined', () => { @@ -20,20 +23,30 @@ describe('validators', () => { expect(() => validateFindCommentsPagination({ page: 100 })).not.toThrowError(); }); + it('does not throw if page and perPage are defined and valid', () => { + expect(() => validateFindCommentsPagination({ page: 2, perPage: 100 })).not.toThrowError(); + }); + it('returns if page and perPage are undefined', () => { expect(() => validateFindCommentsPagination({})).not.toThrowError(); }); + it('returns if perPage < 0', () => { + expect(() => validateFindCommentsPagination({ perPage: -1 })).not.toThrowError(); + }); + it('throws if page > 10k', () => { expect(() => validateFindCommentsPagination({ page: 10001 })).toThrow(ERROR_MSG); }); - it('throws if perPage > 10k', () => { - expect(() => validateFindCommentsPagination({ perPage: 10001 })).toThrowError(ERROR_MSG); + it('throws if perPage > 100', () => { + expect(() => + validateFindCommentsPagination({ perPage: MAX_COMMENTS_PER_PAGE + 1 }) + ).toThrowError(ERROR_MSG_PER_PAGE); }); it('throws if page * perPage > 10k', () => { - expect(() => validateFindCommentsPagination({ page: 10, perPage: 1001 })).toThrow(ERROR_MSG); + expect(() => validateFindCommentsPagination({ page: 101, perPage: 100 })).toThrow(ERROR_MSG); }); }); }); diff --git a/x-pack/plugins/cases/server/client/attachments/validators.ts b/x-pack/plugins/cases/server/client/attachments/validators.ts index 770d9d8e88c0..ea38fa71e702 100644 --- a/x-pack/plugins/cases/server/client/attachments/validators.ts +++ b/x-pack/plugins/cases/server/client/attachments/validators.ts @@ -6,7 +6,7 @@ */ import Boom from '@hapi/boom'; -import { MAX_DOCS_PER_PAGE } from '../../../common/constants'; +import { MAX_DOCS_PER_PAGE, MAX_COMMENTS_PER_PAGE } from '../../../common/constants'; import { isCommentRequestTypeExternalReference, isCommentRequestTypePersistableState, @@ -51,7 +51,13 @@ export const validateFindCommentsPagination = (params?: FindCommentsQueryParams) const pageAsNumber = params.page ?? 0; const perPageAsNumber = params.perPage ?? 0; - if (Math.max(pageAsNumber, perPageAsNumber, pageAsNumber * perPageAsNumber) > MAX_DOCS_PER_PAGE) { + if (perPageAsNumber > MAX_COMMENTS_PER_PAGE) { + throw Boom.badRequest( + `The provided perPage value was too high. The maximum allowed perPage value is ${MAX_COMMENTS_PER_PAGE}.` + ); + } + + if (Math.max(pageAsNumber, pageAsNumber * perPageAsNumber) > MAX_DOCS_PER_PAGE) { throw Boom.badRequest( 'The number of documents is too high. Paginating through more than 10,000 documents is not possible.' ); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts index 267f5472e6eb..6da8cfccf135 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import type SuperTest from 'supertest'; -import { MAX_DOCS_PER_PAGE } from '@kbn/cases-plugin/common/constants'; +import { MAX_COMMENTS_PER_PAGE } from '@kbn/cases-plugin/common/constants'; import { Alerts, createCaseAttachAlertAndDeleteCase, @@ -170,7 +170,7 @@ export default ({ getService }: FtrProviderContext): void => { supertest: supertestWithoutAuth, caseId: postedCase.id, query: { - perPage: MAX_DOCS_PER_PAGE, + perPage: MAX_COMMENTS_PER_PAGE, }, }), ]); @@ -210,14 +210,14 @@ export default ({ getService }: FtrProviderContext): void => { supertest: supertestWithoutAuth, caseId: postedCase1.id, query: { - perPage: MAX_DOCS_PER_PAGE, + perPage: MAX_COMMENTS_PER_PAGE, }, }), findAttachments({ supertest: supertestWithoutAuth, caseId: postedCase2.id, query: { - perPage: MAX_DOCS_PER_PAGE, + perPage: MAX_COMMENTS_PER_PAGE, }, }), ]); @@ -457,7 +457,7 @@ export default ({ getService }: FtrProviderContext): void => { supertest: supertestWithoutAuth, caseId: postedCase.id, query: { - perPage: MAX_DOCS_PER_PAGE, + perPage: MAX_COMMENTS_PER_PAGE, }, auth: { user: secAllUser, space: 'space1' }, }), diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/find_comments.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/find_comments.ts index a218350ec95c..761959db29f6 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/find_comments.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/find_comments.ts @@ -114,7 +114,7 @@ export default ({ getService }: FtrProviderContext): void => { { name: 'field is wrong type', queryParams: { perPage: true } }, { name: 'field is unknown', queryParams: { foo: 'bar' } }, { name: 'page > 10k', queryParams: { page: 10001 } }, - { name: 'perPage > 10k', queryParams: { perPage: 10001 } }, + { name: 'perPage > 100', queryParams: { perPage: 101 } }, { name: 'page * perPage > 10k', queryParams: { page: 2, perPage: 9001 } }, ]) { it(`400s when ${errorScenario.name}`, async () => {