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

[Cases] Restrict searchFields, sortField and remove rootSearchFields from find_cases API #162245

Merged
60 changes: 57 additions & 3 deletions x-pack/plugins/cases/common/api/cases/case.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { PathReporter } from 'io-ts/lib/PathReporter';
import { ConnectorTypes } from '../../types/domain/connector/v1';
import {
RelatedCaseInfoRt,
Expand All @@ -25,6 +26,8 @@ import {
CasesRt,
CasesFindResponseRt,
CaseResolveResponseRt,
CasesFindRequestSearchFieldsRt,
CasesFindRequestSortFieldsRt,
} from './case';
import { CommentType } from './comment';
import { CaseStatuses } from './status';
Expand Down Expand Up @@ -336,11 +339,10 @@ describe('Case', () => {
page: '1',
perPage: '10',
search: 'search text',
searchFields: 'closed_by.username',
rootSearchFields: ['_id'],
searchFields: ['title', 'description'],
to: '1w',
sortOrder: 'desc',
sortField: 'created_at',
sortField: 'createdAt',
owner: 'cases',
};

Expand All @@ -361,6 +363,58 @@ describe('Case', () => {
right: { ...defaultRequest, page: 1, perPage: 10 },
});
});

const searchFields = Object.keys(CasesFindRequestSearchFieldsRt.keys);

it.each(searchFields)('succeeds with %s as searchFields', (field) => {
const query = CasesFindRequestRt.decode({ ...defaultRequest, searchFields: field });

expect(query).toStrictEqual({
_tag: 'Right',
right: { ...defaultRequest, searchFields: field, page: 1, perPage: 10 },
});
});

const sortFields = Object.keys(CasesFindRequestSortFieldsRt.keys);

it.each(sortFields)('succeeds with %s as sortField', (sortField) => {
const query = CasesFindRequestRt.decode({ ...defaultRequest, sortField });

expect(query).toStrictEqual({
_tag: 'Right',
right: { ...defaultRequest, sortField, page: 1, perPage: 10 },
});
});

it('removes rootSearchField when passed', () => {
expect(
PathReporter.report(
CasesFindRequestRt.decode({ ...defaultRequest, rootSearchField: ['foobar'] })
)
).toContain('No errors!');
});

describe('errors', () => {
it('throws error when invalid searchField passed', () => {
expect(
PathReporter.report(
CasesFindRequestRt.decode({ ...defaultRequest, searchFields: 'foobar' })
)
).not.toContain('No errors!');
});

it('throws error when invalid sortField passed', () => {
expect(
PathReporter.report(CasesFindRequestRt.decode({ ...defaultRequest, sortField: 'foobar' }))
).not.toContain('No errors!');
});

it('succeeds when valid parameters passed', () => {
expect(PathReporter.report(CasesFindRequestRt.decode(defaultRequest))).toContain(
'No errors!'
);
});
});
});

describe('CasesByAlertIDRequestRt', () => {
Expand Down
42 changes: 13 additions & 29 deletions x-pack/plugins/cases/common/api/cases/case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,32 +205,19 @@ export const CasePostRequestRt = rt.intersection([
),
]);

const CasesFindRequestSearchFieldsRt = rt.keyof({
'closed_by.username': null,
'closed_by.full_name': null,
'closed_by.email': null,
'closed_by.profile_uid': null,
'created_by.username': null,
'created_by.full_name': null,
'created_by.email': null,
'created_by.profile_uid': null,
export const CasesFindRequestSearchFieldsRt = rt.keyof({
description: null,
'connector.name': null,
'connector.type': null,
'external_service.pushed_by.username': null,
'external_service.pushed_by.full_name': null,
'external_service.pushed_by.email': null,
'external_service.pushed_by.profile_uid': null,
'external_service.connector_name': null,
'external_service.external_id': null,
'external_service.external_title': null,
'external_service.external_url': null,
title: null,
'title.keyword': null,
js-jankisalvi marked this conversation as resolved.
Show resolved Hide resolved
'updated_by.username': null,
'updated_by.full_name': null,
'updated_by.email': null,
'updated_by.profile_uid': null,
});

export const CasesFindRequestSortFieldsRt = rt.keyof({
title: null,
category: null,
createdAt: null,
updatedAt: null,
closedAt: null,
status: null,
severity: null,
});

export const CasesFindRequestRt = rt.intersection([
Expand Down Expand Up @@ -307,15 +294,11 @@ export const CasesFindRequestRt = rt.intersection([
rt.array(CasesFindRequestSearchFieldsRt),
CasesFindRequestSearchFieldsRt,
]),
/**
* The root fields to perform the simple_query_string parsed query against
*/
rootSearchFields: rt.array(rt.string),
/**
* The field to use for sorting the found objects.
*
*/
sortField: rt.string,
sortField: CasesFindRequestSortFieldsRt,
/**
* The order to sort by
*/
Expand Down Expand Up @@ -551,6 +534,7 @@ export type Cases = rt.TypeOf<typeof CasesRt>;
export type CasesDeleteRequest = rt.TypeOf<typeof CasesDeleteRequestRt>;
export type CasesByAlertIDRequest = rt.TypeOf<typeof CasesByAlertIDRequestRt>;
export type CasesFindRequest = rt.TypeOf<typeof CasesFindRequestRt>;
export type CasesFindRequestSortFields = rt.TypeOf<typeof CasesFindRequestSortFieldsRt>;
export type CasesFindResponse = rt.TypeOf<typeof CasesFindResponseRt>;
export type CasePatchRequest = rt.TypeOf<typeof CasePatchRequestRt>;
export type CasesPatchRequest = rt.TypeOf<typeof CasesPatchRequestRt>;
Expand Down
62 changes: 22 additions & 40 deletions x-pack/plugins/cases/docs/openapi/bundled.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,26 @@
"url": "https://www.elastic.co/licensing/elastic-license"
}
},
"tags": [
{
"name": "cases",
"description": "Case APIs enable you to open and track issues."
}
],
"servers": [
{
"url": "http://localhost:5601",
"description": "local"
}
],
"security": [
{
"basicAuth": []
},
{
"apiKeyAuth": []
}
],
"tags": [
{
"name": "cases",
"description": "Case APIs enable you to open and track issues."
}
],
"paths": {
"/api/cases": {
"post": {
Expand Down Expand Up @@ -3977,7 +3985,12 @@
"type": "string",
"enum": [
"createdAt",
"updatedAt"
"updatedAt",
"closedAt",
"title",
"category",
"status",
"severity"
],
"default": "createdAt"
},
Expand Down Expand Up @@ -5286,31 +5299,8 @@
"type": "string",
"description": "The fields to perform the `simple_query_string` parsed query against.",
"enum": [
"closed_by.username",
"closed_by.full_name",
"closed_by.email",
"closed_by.profile_uid",
"created_by.username",
"created_by.full_name",
"created_by.email",
"created_by.profile_uid",
"description",
"connector.name",
"connector.type",
"external_service.pushed_by.username",
"external_service.pushed_by.full_name",
"external_service.pushed_by.email",
"external_service.pushed_by.profile_uid",
"external_service.connector_name",
"external_service.external_id",
"external_service.external_title",
"external_service.external_url",
"title",
"title.keyword",
"updated_by.username",
"updated_by.full_name",
"updated_by.email",
"updated_by.profile_uid"
"title"
]
},
"closure_types": {
Expand Down Expand Up @@ -7151,13 +7141,5 @@
]
}
}
},
"security": [
{
"basicAuth": []
},
{
"apiKeyAuth": []
}
]
}
}
40 changes: 11 additions & 29 deletions x-pack/plugins/cases/docs/openapi/bundled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ info:
license:
name: Elastic License 2.0
url: https://www.elastic.co/licensing/elastic-license
tags:
- name: cases
description: Case APIs enable you to open and track issues.
servers:
- url: http://localhost:5601
description: local
security:
- basicAuth: []
- apiKeyAuth: []
tags:
- name: cases
description: Case APIs enable you to open and track issues.
paths:
/api/cases:
post:
Expand Down Expand Up @@ -2427,6 +2430,11 @@ components:
enum:
- createdAt
- updatedAt
- closedAt
- title
- category
- status
- severity
default: createdAt
example: updatedAt
sort_order:
Expand Down Expand Up @@ -3392,31 +3400,8 @@ components:
type: string
description: The fields to perform the `simple_query_string` parsed query against.
enum:
- closed_by.username
- closed_by.full_name
- closed_by.email
- closed_by.profile_uid
- created_by.username
- created_by.full_name
- created_by.email
- created_by.profile_uid
- description
- connector.name
- connector.type
- external_service.pushed_by.username
- external_service.pushed_by.full_name
- external_service.pushed_by.email
- external_service.pushed_by.profile_uid
- external_service.connector_name
- external_service.external_id
- external_service.external_title
- external_service.external_url
- title
- title.keyword
- updated_by.username
- updated_by.full_name
- updated_by.email
- updated_by.profile_uid
closure_types:
type: string
description: Indicates whether a case is automatically closed when it is pushed to external systems (`close-by-pushing`) or not automatically closed (`close-by-user`).
Expand Down Expand Up @@ -4768,6 +4753,3 @@ components:
isPreconfigured: false
isDeprecated: false
referencedByCount: 0
security:
- basicAuth: []
- apiKeyAuth: []
Original file line number Diff line number Diff line change
@@ -1,28 +1,5 @@
type: string
description: The fields to perform the `simple_query_string` parsed query against.
enum:
- closed_by.username
- closed_by.full_name
- closed_by.email
- closed_by.profile_uid
- created_by.username
- created_by.full_name
- created_by.email
- created_by.profile_uid
- description
- connector.name
- connector.type
- external_service.pushed_by.username
- external_service.pushed_by.full_name
- external_service.pushed_by.email
- external_service.pushed_by.profile_uid
- external_service.connector_name
- external_service.external_id
- external_service.external_title
- external_service.external_url
- title
- title.keyword
- updated_by.username
- updated_by.full_name
- updated_by.email
- updated_by.profile_uid
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ schema:
enum:
- createdAt
- updatedAt
- closedAt
- title
- category
- status
- severity
default: createdAt
example: updatedAt
Loading