mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
Adds two more packages and moves files into the packages (#100375)
## Summary * Adds package `kbn-securitysolution-list-api` * Adds package `kbn-securitysolution-list-hooks` * Moves files into the packages * Moves a few additional types into the other packages such as the `kbn-securitysolution-io-ts-types` package to remove more things from the shard_export/shared_import between lists and security solution * Removes more duplicated code ### Checklist - [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
This commit is contained in:
parent
3523a937f6
commit
192c8ba743
128 changed files with 1669 additions and 517 deletions
88
packages/kbn-securitysolution-list-api/BUILD.bazel
Normal file
88
packages/kbn-securitysolution-list-api/BUILD.bazel
Normal file
|
@ -0,0 +1,88 @@
|
|||
load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm")
|
||||
|
||||
PKG_BASE_NAME = "kbn-securitysolution-list-api"
|
||||
|
||||
PKG_REQUIRE_NAME = "@kbn/securitysolution-list-api"
|
||||
|
||||
SOURCE_FILES = glob(
|
||||
[
|
||||
"src/**/*.ts",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.test.*",
|
||||
"**/*.mock.*",
|
||||
],
|
||||
)
|
||||
|
||||
SRCS = SOURCE_FILES
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = SRCS,
|
||||
)
|
||||
|
||||
NPM_MODULE_EXTRA_FILES = [
|
||||
"package.json",
|
||||
"README.md",
|
||||
]
|
||||
|
||||
SRC_DEPS = [
|
||||
"//packages/kbn-securitysolution-io-ts-utils",
|
||||
"//packages/kbn-securitysolution-io-ts-list-types",
|
||||
"@npm//fp-ts",
|
||||
"@npm//io-ts",
|
||||
"@npm//tslib",
|
||||
]
|
||||
|
||||
TYPES_DEPS = [
|
||||
"@npm//@types/jest",
|
||||
"@npm//@types/node",
|
||||
]
|
||||
|
||||
DEPS = SRC_DEPS + TYPES_DEPS
|
||||
|
||||
ts_config(
|
||||
name = "tsconfig",
|
||||
src = "tsconfig.json",
|
||||
deps = [
|
||||
"//:tsconfig.base.json",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "tsc",
|
||||
srcs = SRCS,
|
||||
args = ["--pretty"],
|
||||
declaration = True,
|
||||
declaration_map = True,
|
||||
incremental = True,
|
||||
out_dir = "target",
|
||||
root_dir = "src",
|
||||
source_map = True,
|
||||
tsconfig = ":tsconfig",
|
||||
deps = DEPS,
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = PKG_BASE_NAME,
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
srcs = NPM_MODULE_EXTRA_FILES,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":tsc"] + DEPS,
|
||||
)
|
||||
|
||||
pkg_npm(
|
||||
name = "npm_module",
|
||||
deps = [
|
||||
":%s" % PKG_BASE_NAME,
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build",
|
||||
srcs = [
|
||||
":npm_module",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
4
packages/kbn-securitysolution-list-api/README.md
Normal file
4
packages/kbn-securitysolution-list-api/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# kbn-securitysolution-list-api
|
||||
|
||||
This is where the REST API for the list plugin lives
|
||||
|
13
packages/kbn-securitysolution-list-api/jest.config.js
Normal file
13
packages/kbn-securitysolution-list-api/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../..',
|
||||
roots: ['<rootDir>/packages/kbn-securitysolution-list-api'],
|
||||
};
|
9
packages/kbn-securitysolution-list-api/package.json
Normal file
9
packages/kbn-securitysolution-list-api/package.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@kbn/securitysolution-list-api",
|
||||
"version": "1.0.0",
|
||||
"description": "security solution list REST API",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0",
|
||||
"main": "./target/index.js",
|
||||
"types": "./target/index.d.ts",
|
||||
"private": true
|
||||
}
|
15
packages/kbn-securitysolution-list-api/src/api/index.test.ts
Normal file
15
packages/kbn-securitysolution-list-api/src/api/index.test.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
describe('Exceptions Lists API', () => {
|
||||
test('we should port these tests', () => {
|
||||
// See the file outside of this at: x-pack/plugins/lists/public/exceptions/api.test.ts
|
||||
// for the tests. We cannot port the tests over until we move the mocks into their own package
|
||||
// and possibly core mocks end up within packages.
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
564
packages/kbn-securitysolution-list-api/src/api/index.ts
Normal file
564
packages/kbn-securitysolution-list-api/src/api/index.ts
Normal file
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { chain, fromEither, tryCatch } from 'fp-ts/lib/TaskEither';
|
||||
import { flow } from 'fp-ts/lib/function';
|
||||
import { validateEither } from '@kbn/securitysolution-io-ts-utils';
|
||||
import {
|
||||
CreateEndpointListSchema,
|
||||
ExceptionListItemSchema,
|
||||
ExceptionListSchema,
|
||||
FoundExceptionListItemSchema,
|
||||
FoundExceptionListSchema,
|
||||
createEndpointListSchema,
|
||||
exceptionListItemSchema,
|
||||
exceptionListSchema,
|
||||
foundExceptionListItemSchema,
|
||||
foundExceptionListSchema,
|
||||
AddEndpointExceptionListProps,
|
||||
AddExceptionListItemProps,
|
||||
AddExceptionListProps,
|
||||
ApiCallByIdProps,
|
||||
ApiCallByListIdProps,
|
||||
ApiCallFetchExceptionListsProps,
|
||||
ExportExceptionListProps,
|
||||
UpdateExceptionListItemProps,
|
||||
UpdateExceptionListProps,
|
||||
} from '@kbn/securitysolution-io-ts-list-types';
|
||||
|
||||
import { toError, toPromise } from '../fp_utils';
|
||||
import {
|
||||
ENDPOINT_LIST_URL,
|
||||
EXCEPTION_LIST_ITEM_URL,
|
||||
EXCEPTION_LIST_NAMESPACE,
|
||||
EXCEPTION_LIST_NAMESPACE_AGNOSTIC,
|
||||
EXCEPTION_LIST_URL,
|
||||
} from '../constants';
|
||||
|
||||
/**
|
||||
* Add new ExceptionList
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param list exception list to add
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*
|
||||
*/
|
||||
const addExceptionList = async ({
|
||||
http,
|
||||
list,
|
||||
signal,
|
||||
}: AddExceptionListProps): Promise<ExceptionListSchema> =>
|
||||
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
|
||||
body: JSON.stringify(list),
|
||||
method: 'POST',
|
||||
signal,
|
||||
});
|
||||
|
||||
const addExceptionListWithValidation = async ({
|
||||
http,
|
||||
list,
|
||||
signal,
|
||||
}: AddExceptionListProps): Promise<ExceptionListSchema> =>
|
||||
flow(
|
||||
() =>
|
||||
tryCatch(
|
||||
() =>
|
||||
addExceptionList({
|
||||
http,
|
||||
list,
|
||||
signal,
|
||||
}),
|
||||
toError
|
||||
),
|
||||
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { addExceptionListWithValidation as addExceptionList };
|
||||
|
||||
/**
|
||||
* Add new ExceptionListItem
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param listItem exception list item to add
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*
|
||||
*/
|
||||
const addExceptionListItem = async ({
|
||||
http,
|
||||
listItem,
|
||||
signal,
|
||||
}: AddExceptionListItemProps): Promise<ExceptionListItemSchema> =>
|
||||
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
|
||||
body: JSON.stringify(listItem),
|
||||
method: 'POST',
|
||||
signal,
|
||||
});
|
||||
|
||||
const addExceptionListItemWithValidation = async ({
|
||||
http,
|
||||
listItem,
|
||||
signal,
|
||||
}: AddExceptionListItemProps): Promise<ExceptionListItemSchema> =>
|
||||
flow(
|
||||
() =>
|
||||
tryCatch(
|
||||
() =>
|
||||
addExceptionListItem({
|
||||
http,
|
||||
listItem,
|
||||
signal,
|
||||
}),
|
||||
toError
|
||||
),
|
||||
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { addExceptionListItemWithValidation as addExceptionListItem };
|
||||
|
||||
/**
|
||||
* Update existing ExceptionList
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param list exception list to add
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*
|
||||
*/
|
||||
const updateExceptionList = async ({
|
||||
http,
|
||||
list,
|
||||
signal,
|
||||
}: UpdateExceptionListProps): Promise<ExceptionListSchema> =>
|
||||
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
|
||||
body: JSON.stringify(list),
|
||||
method: 'PUT',
|
||||
signal,
|
||||
});
|
||||
|
||||
const updateExceptionListWithValidation = async ({
|
||||
http,
|
||||
list,
|
||||
signal,
|
||||
}: UpdateExceptionListProps): Promise<ExceptionListSchema> =>
|
||||
flow(
|
||||
() =>
|
||||
tryCatch(
|
||||
() =>
|
||||
updateExceptionList({
|
||||
http,
|
||||
list,
|
||||
signal,
|
||||
}),
|
||||
toError
|
||||
),
|
||||
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { updateExceptionListWithValidation as updateExceptionList };
|
||||
|
||||
/**
|
||||
* Update existing ExceptionListItem
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param listItem exception list item to add
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*
|
||||
*/
|
||||
const updateExceptionListItem = async ({
|
||||
http,
|
||||
listItem,
|
||||
signal,
|
||||
}: UpdateExceptionListItemProps): Promise<ExceptionListItemSchema> =>
|
||||
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
|
||||
body: JSON.stringify(listItem),
|
||||
method: 'PUT',
|
||||
signal,
|
||||
});
|
||||
|
||||
const updateExceptionListItemWithValidation = async ({
|
||||
http,
|
||||
listItem,
|
||||
signal,
|
||||
}: UpdateExceptionListItemProps): Promise<ExceptionListItemSchema> =>
|
||||
flow(
|
||||
() =>
|
||||
tryCatch(
|
||||
() =>
|
||||
updateExceptionListItem({
|
||||
http,
|
||||
listItem,
|
||||
signal,
|
||||
}),
|
||||
toError
|
||||
),
|
||||
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { updateExceptionListItemWithValidation as updateExceptionListItem };
|
||||
|
||||
/**
|
||||
* Fetch all ExceptionLists (optionally by namespaceType)
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param namespaceTypes ExceptionList namespace_types of lists to find
|
||||
* @param filters search bar filters
|
||||
* @param pagination optional
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if request params or response is not OK
|
||||
*/
|
||||
const fetchExceptionLists = async ({
|
||||
http,
|
||||
filters,
|
||||
namespaceTypes,
|
||||
pagination,
|
||||
signal,
|
||||
}: ApiCallFetchExceptionListsProps): Promise<FoundExceptionListSchema> => {
|
||||
const query = {
|
||||
filter: filters,
|
||||
namespace_type: namespaceTypes,
|
||||
page: pagination.page ? `${pagination.page}` : '1',
|
||||
per_page: pagination.perPage ? `${pagination.perPage}` : '20',
|
||||
sort_field: 'exception-list.created_at',
|
||||
sort_order: 'desc',
|
||||
};
|
||||
|
||||
return http.fetch<FoundExceptionListSchema>(`${EXCEPTION_LIST_URL}/_find`, {
|
||||
method: 'GET',
|
||||
query,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
const fetchExceptionListsWithValidation = async ({
|
||||
filters,
|
||||
http,
|
||||
namespaceTypes,
|
||||
pagination,
|
||||
signal,
|
||||
}: ApiCallFetchExceptionListsProps): Promise<FoundExceptionListSchema> =>
|
||||
flow(
|
||||
() =>
|
||||
tryCatch(
|
||||
() =>
|
||||
fetchExceptionLists({
|
||||
filters,
|
||||
http,
|
||||
namespaceTypes,
|
||||
pagination,
|
||||
signal,
|
||||
}),
|
||||
toError
|
||||
),
|
||||
chain((response) => fromEither(validateEither(foundExceptionListSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { fetchExceptionListsWithValidation as fetchExceptionLists };
|
||||
|
||||
/**
|
||||
* Fetch an ExceptionList by providing a ExceptionList ID
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param id ExceptionList ID (not list_id)
|
||||
* @param namespaceType ExceptionList namespace_type
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*/
|
||||
const fetchExceptionListById = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
|
||||
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
|
||||
method: 'GET',
|
||||
query: { id, namespace_type: namespaceType },
|
||||
signal,
|
||||
});
|
||||
|
||||
const fetchExceptionListByIdWithValidation = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
|
||||
flow(
|
||||
() =>
|
||||
tryCatch(
|
||||
() =>
|
||||
fetchExceptionListById({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}),
|
||||
toError
|
||||
),
|
||||
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { fetchExceptionListByIdWithValidation as fetchExceptionListById };
|
||||
|
||||
/**
|
||||
* Fetch an ExceptionList's ExceptionItems by providing a ExceptionList list_id
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param listIds ExceptionList list_ids (not ID)
|
||||
* @param namespaceTypes ExceptionList namespace_types
|
||||
* @param filterOptions optional - filter by field or tags
|
||||
* @param pagination optional
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*/
|
||||
const fetchExceptionListsItemsByListIds = async ({
|
||||
http,
|
||||
listIds,
|
||||
namespaceTypes,
|
||||
filterOptions,
|
||||
pagination,
|
||||
signal,
|
||||
}: ApiCallByListIdProps): Promise<FoundExceptionListItemSchema> => {
|
||||
const filters: string = filterOptions
|
||||
.map<string>((filter, index) => {
|
||||
const namespace = namespaceTypes[index];
|
||||
const filterNamespace =
|
||||
namespace === 'agnostic' ? EXCEPTION_LIST_NAMESPACE_AGNOSTIC : EXCEPTION_LIST_NAMESPACE;
|
||||
const formattedFilters = [
|
||||
...(filter.filter.length
|
||||
? [`${filterNamespace}.attributes.entries.field:${filter.filter}*`]
|
||||
: []),
|
||||
...(filter.tags.length
|
||||
? filter.tags.map((t) => `${filterNamespace}.attributes.tags:${t}`)
|
||||
: []),
|
||||
];
|
||||
|
||||
return formattedFilters.join(' AND ');
|
||||
})
|
||||
.join(',');
|
||||
|
||||
const query = {
|
||||
list_id: listIds.join(','),
|
||||
namespace_type: namespaceTypes.join(','),
|
||||
page: pagination.page ? `${pagination.page}` : '1',
|
||||
per_page: pagination.perPage ? `${pagination.perPage}` : '20',
|
||||
sort_field: 'exception-list.created_at',
|
||||
sort_order: 'desc',
|
||||
...(filters.trim() !== '' ? { filter: filters } : {}),
|
||||
};
|
||||
|
||||
return http.fetch<FoundExceptionListItemSchema>(`${EXCEPTION_LIST_ITEM_URL}/_find`, {
|
||||
method: 'GET',
|
||||
query,
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
const fetchExceptionListsItemsByListIdsWithValidation = async ({
|
||||
filterOptions,
|
||||
http,
|
||||
listIds,
|
||||
namespaceTypes,
|
||||
pagination,
|
||||
signal,
|
||||
}: ApiCallByListIdProps): Promise<FoundExceptionListItemSchema> =>
|
||||
flow(
|
||||
() =>
|
||||
tryCatch(
|
||||
() =>
|
||||
fetchExceptionListsItemsByListIds({
|
||||
filterOptions,
|
||||
http,
|
||||
listIds,
|
||||
namespaceTypes,
|
||||
pagination,
|
||||
signal,
|
||||
}),
|
||||
toError
|
||||
),
|
||||
chain((response) => fromEither(validateEither(foundExceptionListItemSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { fetchExceptionListsItemsByListIdsWithValidation as fetchExceptionListsItemsByListIds };
|
||||
|
||||
/**
|
||||
* Fetch an ExceptionListItem by providing a ExceptionListItem ID
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param id ExceptionListItem ID (not item_id)
|
||||
* @param namespaceType ExceptionList namespace_type
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*/
|
||||
const fetchExceptionListItemById = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
|
||||
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
|
||||
method: 'GET',
|
||||
query: { id, namespace_type: namespaceType },
|
||||
signal,
|
||||
});
|
||||
|
||||
const fetchExceptionListItemByIdWithValidation = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
|
||||
flow(
|
||||
() => tryCatch(() => fetchExceptionListItemById({ http, id, namespaceType, signal }), toError),
|
||||
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { fetchExceptionListItemByIdWithValidation as fetchExceptionListItemById };
|
||||
|
||||
/**
|
||||
* Delete an ExceptionList by providing a ExceptionList ID
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param id ExceptionList ID (not list_id)
|
||||
* @param namespaceType ExceptionList namespace_type
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*/
|
||||
const deleteExceptionListById = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
|
||||
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
|
||||
method: 'DELETE',
|
||||
query: { id, namespace_type: namespaceType },
|
||||
signal,
|
||||
});
|
||||
|
||||
const deleteExceptionListByIdWithValidation = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
|
||||
flow(
|
||||
() => tryCatch(() => deleteExceptionListById({ http, id, namespaceType, signal }), toError),
|
||||
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { deleteExceptionListByIdWithValidation as deleteExceptionListById };
|
||||
|
||||
/**
|
||||
* Delete an ExceptionListItem by providing a ExceptionListItem ID
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param id ExceptionListItem ID (not item_id)
|
||||
* @param namespaceType ExceptionList namespace_type
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*/
|
||||
const deleteExceptionListItemById = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
|
||||
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
|
||||
method: 'DELETE',
|
||||
query: { id, namespace_type: namespaceType },
|
||||
signal,
|
||||
});
|
||||
|
||||
const deleteExceptionListItemByIdWithValidation = async ({
|
||||
http,
|
||||
id,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
|
||||
flow(
|
||||
() => tryCatch(() => deleteExceptionListItemById({ http, id, namespaceType, signal }), toError),
|
||||
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { deleteExceptionListItemByIdWithValidation as deleteExceptionListItemById };
|
||||
|
||||
/**
|
||||
* Add new Endpoint ExceptionList
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*
|
||||
*/
|
||||
const addEndpointExceptionList = async ({
|
||||
http,
|
||||
signal,
|
||||
}: AddEndpointExceptionListProps): Promise<CreateEndpointListSchema> =>
|
||||
http.fetch<ExceptionListItemSchema>(ENDPOINT_LIST_URL, {
|
||||
method: 'POST',
|
||||
signal,
|
||||
});
|
||||
|
||||
const addEndpointExceptionListWithValidation = async ({
|
||||
http,
|
||||
signal,
|
||||
}: AddEndpointExceptionListProps): Promise<CreateEndpointListSchema> =>
|
||||
flow(
|
||||
() => tryCatch(() => addEndpointExceptionList({ http, signal }), toError),
|
||||
chain((response) => fromEither(validateEither(createEndpointListSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { addEndpointExceptionListWithValidation as addEndpointExceptionList };
|
||||
|
||||
/**
|
||||
* Fetch an ExceptionList by providing a ExceptionList ID
|
||||
*
|
||||
* @param http Kibana http service
|
||||
* @param id ExceptionList ID (not list_id)
|
||||
* @param listId ExceptionList LIST_ID (not id)
|
||||
* @param namespaceType ExceptionList namespace_type
|
||||
* @param signal to cancel request
|
||||
*
|
||||
* @throws An error if response is not OK
|
||||
*/
|
||||
export const exportExceptionList = async ({
|
||||
http,
|
||||
id,
|
||||
listId,
|
||||
namespaceType,
|
||||
signal,
|
||||
}: ExportExceptionListProps): Promise<Blob> =>
|
||||
http.fetch<Blob>(`${EXCEPTION_LIST_URL}/_export`, {
|
||||
method: 'GET',
|
||||
query: { id, list_id: listId, namespace_type: namespaceType },
|
||||
signal,
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
// TODO: These should be all replaced with constants from a shared kbn constants package
|
||||
|
||||
export const LIST_URL = '/api/lists';
|
||||
export const LIST_INDEX = `${LIST_URL}/index`;
|
||||
export const LIST_ITEM_URL = `${LIST_URL}/items`;
|
||||
export const LIST_PRIVILEGES_URL = `${LIST_URL}/privileges`;
|
||||
|
||||
/**
|
||||
* Exception list routes
|
||||
*/
|
||||
export const EXCEPTION_LIST_URL = '/api/exception_lists';
|
||||
export const EXCEPTION_LIST_ITEM_URL = '/api/exception_lists/items';
|
||||
|
||||
/**
|
||||
* Exception list spaces
|
||||
*/
|
||||
export const EXCEPTION_LIST_NAMESPACE_AGNOSTIC = 'exception-list-agnostic';
|
||||
export const EXCEPTION_LIST_NAMESPACE = 'exception-list';
|
||||
|
||||
/**
|
||||
* Specific routes for the single global space agnostic endpoint list
|
||||
*/
|
||||
export const ENDPOINT_LIST_URL = '/api/endpoint_list';
|
||||
|
||||
/**
|
||||
* Specific routes for the single global space agnostic endpoint list. These are convenience
|
||||
* routes where they are going to try and create the global space agnostic endpoint list if it
|
||||
* does not exist yet or if it was deleted at some point and re-create it before adding items to
|
||||
* the list
|
||||
*/
|
||||
export const ENDPOINT_LIST_ITEM_URL = '/api/endpoint_list/items';
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { tryCatch } from 'fp-ts/lib/TaskEither';
|
||||
|
||||
import { toPromise } from '.';
|
||||
|
||||
describe('toPromise', () => {
|
||||
it('rejects with left if TaskEither is left', async () => {
|
||||
const task = tryCatch(() => Promise.reject(new Error('whoops')), String);
|
||||
|
||||
await expect(toPromise(task)).rejects.toEqual('Error: whoops');
|
||||
});
|
||||
|
||||
it('resolves with right if TaskEither is right', async () => {
|
||||
const task = tryCatch(() => Promise.resolve('success'), String);
|
||||
|
||||
await expect(toPromise(task)).resolves.toEqual('success');
|
||||
});
|
||||
});
|
24
packages/kbn-securitysolution-list-api/src/fp_utils/index.ts
Normal file
24
packages/kbn-securitysolution-list-api/src/fp_utils/index.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { TaskEither } from 'fp-ts/lib/TaskEither';
|
||||
import { fold } from 'fp-ts/lib/Either';
|
||||
|
||||
// TODO: This is copied in a few other spots and probably should live within its own kbn package
|
||||
// rather than living here. A package such as kbn-security-solution-fp-utils
|
||||
export const toPromise = async <E, A>(taskEither: TaskEither<E, A>): Promise<A> =>
|
||||
pipe(
|
||||
await taskEither(),
|
||||
fold(
|
||||
(e) => Promise.reject(e),
|
||||
(a) => Promise.resolve(a)
|
||||
)
|
||||
);
|
||||
|
||||
export const toError = (e: unknown): Error => (e instanceof Error ? e : new Error(String(e)));
|
11
packages/kbn-securitysolution-list-api/src/index.ts
Normal file
11
packages/kbn-securitysolution-list-api/src/index.ts
Normal 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './api';
|
||||
export * from './fp_utils';
|
||||
export * from './list_api';
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
describe('Value Lists API', () => {
|
||||
test('Tests should be ported', () => {
|
||||
// TODO: Port all the tests from: x-pack/plugins/lists/public/lists/api.test.ts here once mocks are figured out and kbn package mocks are figured out
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
230
packages/kbn-securitysolution-list-api/src/list_api/index.ts
Normal file
230
packages/kbn-securitysolution-list-api/src/list_api/index.ts
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { chain, fromEither, map, tryCatch } from 'fp-ts/lib/TaskEither';
|
||||
import { flow } from 'fp-ts/lib/function';
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { validateEither } from '@kbn/securitysolution-io-ts-utils';
|
||||
import {
|
||||
AcknowledgeSchema,
|
||||
DeleteListSchemaEncoded,
|
||||
ExportListItemQuerySchemaEncoded,
|
||||
FindListSchemaEncoded,
|
||||
FoundListSchema,
|
||||
ImportListItemQuerySchemaEncoded,
|
||||
ImportListItemSchemaEncoded,
|
||||
ListItemIndexExistSchema,
|
||||
ListSchema,
|
||||
acknowledgeSchema,
|
||||
deleteListSchema,
|
||||
exportListItemQuerySchema,
|
||||
findListSchema,
|
||||
foundListSchema,
|
||||
importListItemQuerySchema,
|
||||
importListItemSchema,
|
||||
listItemIndexExistSchema,
|
||||
listSchema,
|
||||
} from '@kbn/securitysolution-io-ts-list-types';
|
||||
import { toError, toPromise } from '../fp_utils';
|
||||
|
||||
import { LIST_INDEX, LIST_ITEM_URL, LIST_PRIVILEGES_URL, LIST_URL } from '../constants';
|
||||
|
||||
import {
|
||||
ApiParams,
|
||||
DeleteListParams,
|
||||
ExportListParams,
|
||||
FindListsParams,
|
||||
ImportListParams,
|
||||
} from './types';
|
||||
|
||||
const findLists = async ({
|
||||
http,
|
||||
cursor,
|
||||
page,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
per_page,
|
||||
signal,
|
||||
}: ApiParams & FindListSchemaEncoded): Promise<FoundListSchema> => {
|
||||
return http.fetch(`${LIST_URL}/_find`, {
|
||||
method: 'GET',
|
||||
query: {
|
||||
cursor,
|
||||
page,
|
||||
per_page,
|
||||
},
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
const findListsWithValidation = async ({
|
||||
cursor,
|
||||
http,
|
||||
pageIndex,
|
||||
pageSize,
|
||||
signal,
|
||||
}: FindListsParams): Promise<FoundListSchema> =>
|
||||
pipe(
|
||||
{
|
||||
cursor: cursor != null ? cursor.toString() : undefined,
|
||||
page: pageIndex != null ? pageIndex.toString() : undefined,
|
||||
per_page: pageSize != null ? pageSize.toString() : undefined,
|
||||
},
|
||||
(payload) => fromEither(validateEither(findListSchema, payload)),
|
||||
chain((payload) => tryCatch(() => findLists({ http, signal, ...payload }), toError)),
|
||||
chain((response) => fromEither(validateEither(foundListSchema, response))),
|
||||
flow(toPromise)
|
||||
);
|
||||
|
||||
export { findListsWithValidation as findLists };
|
||||
|
||||
const importList = async ({
|
||||
file,
|
||||
http,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
list_id,
|
||||
type,
|
||||
signal,
|
||||
}: ApiParams &
|
||||
ImportListItemSchemaEncoded &
|
||||
ImportListItemQuerySchemaEncoded): Promise<ListSchema> => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file as Blob);
|
||||
|
||||
return http.fetch<ListSchema>(`${LIST_ITEM_URL}/_import`, {
|
||||
body: formData,
|
||||
headers: { 'Content-Type': undefined },
|
||||
method: 'POST',
|
||||
query: { list_id, type },
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
const importListWithValidation = async ({
|
||||
file,
|
||||
http,
|
||||
listId,
|
||||
type,
|
||||
signal,
|
||||
}: ImportListParams): Promise<ListSchema> =>
|
||||
pipe(
|
||||
{
|
||||
list_id: listId,
|
||||
type,
|
||||
},
|
||||
(query) => fromEither(validateEither(importListItemQuerySchema, query)),
|
||||
chain((query) =>
|
||||
pipe(
|
||||
fromEither(validateEither(importListItemSchema, { file })),
|
||||
map((body) => ({ ...body, ...query }))
|
||||
)
|
||||
),
|
||||
chain((payload) => tryCatch(() => importList({ http, signal, ...payload }), toError)),
|
||||
chain((response) => fromEither(validateEither(listSchema, response))),
|
||||
toPromise
|
||||
);
|
||||
|
||||
export { importListWithValidation as importList };
|
||||
|
||||
const deleteList = async ({
|
||||
deleteReferences = false,
|
||||
http,
|
||||
id,
|
||||
ignoreReferences = false,
|
||||
signal,
|
||||
}: ApiParams & DeleteListSchemaEncoded): Promise<ListSchema> =>
|
||||
http.fetch<ListSchema>(LIST_URL, {
|
||||
method: 'DELETE',
|
||||
query: { deleteReferences, id, ignoreReferences },
|
||||
signal,
|
||||
});
|
||||
|
||||
const deleteListWithValidation = async ({
|
||||
deleteReferences,
|
||||
http,
|
||||
id,
|
||||
ignoreReferences,
|
||||
signal,
|
||||
}: DeleteListParams): Promise<ListSchema> =>
|
||||
pipe(
|
||||
{ deleteReferences, id, ignoreReferences },
|
||||
(payload) => fromEither(validateEither(deleteListSchema, payload)),
|
||||
chain((payload) => tryCatch(() => deleteList({ http, signal, ...payload }), toError)),
|
||||
chain((response) => fromEither(validateEither(listSchema, response))),
|
||||
flow(toPromise)
|
||||
);
|
||||
|
||||
export { deleteListWithValidation as deleteList };
|
||||
|
||||
const exportList = async ({
|
||||
http,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
list_id,
|
||||
signal,
|
||||
}: ApiParams & ExportListItemQuerySchemaEncoded): Promise<Blob> =>
|
||||
http.fetch<Blob>(`${LIST_ITEM_URL}/_export`, {
|
||||
method: 'POST',
|
||||
query: { list_id },
|
||||
signal,
|
||||
});
|
||||
|
||||
const exportListWithValidation = async ({
|
||||
http,
|
||||
listId,
|
||||
signal,
|
||||
}: ExportListParams): Promise<Blob> =>
|
||||
pipe(
|
||||
{ list_id: listId },
|
||||
(payload) => fromEither(validateEither(exportListItemQuerySchema, payload)),
|
||||
chain((payload) => tryCatch(() => exportList({ http, signal, ...payload }), toError)),
|
||||
flow(toPromise)
|
||||
);
|
||||
|
||||
export { exportListWithValidation as exportList };
|
||||
|
||||
const readListIndex = async ({ http, signal }: ApiParams): Promise<ListItemIndexExistSchema> =>
|
||||
http.fetch<ListItemIndexExistSchema>(LIST_INDEX, {
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
|
||||
const readListIndexWithValidation = async ({
|
||||
http,
|
||||
signal,
|
||||
}: ApiParams): Promise<ListItemIndexExistSchema> =>
|
||||
flow(
|
||||
() => tryCatch(() => readListIndex({ http, signal }), toError),
|
||||
chain((response) => fromEither(validateEither(listItemIndexExistSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { readListIndexWithValidation as readListIndex };
|
||||
|
||||
// TODO add types and validation
|
||||
export const readListPrivileges = async ({ http, signal }: ApiParams): Promise<unknown> =>
|
||||
http.fetch<unknown>(LIST_PRIVILEGES_URL, {
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
|
||||
const createListIndex = async ({ http, signal }: ApiParams): Promise<AcknowledgeSchema> =>
|
||||
http.fetch<AcknowledgeSchema>(LIST_INDEX, {
|
||||
method: 'POST',
|
||||
signal,
|
||||
});
|
||||
|
||||
const createListIndexWithValidation = async ({
|
||||
http,
|
||||
signal,
|
||||
}: ApiParams): Promise<AcknowledgeSchema> =>
|
||||
flow(
|
||||
() => tryCatch(() => createListIndex({ http, signal }), toError),
|
||||
chain((response) => fromEither(validateEither(acknowledgeSchema, response))),
|
||||
flow(toPromise)
|
||||
)();
|
||||
|
||||
export { createListIndexWithValidation as createListIndex };
|
44
packages/kbn-securitysolution-list-api/src/list_api/types.ts
Normal file
44
packages/kbn-securitysolution-list-api/src/list_api/types.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { Type } from '@kbn/securitysolution-io-ts-list-types';
|
||||
|
||||
// TODO: Replace these with kbn packaged versions once we have those available to us
|
||||
// These originally came from this location below before moving them to this hacked "any" types:
|
||||
// import { HttpStart, NotificationsStart } from '../../../../../src/core/public';
|
||||
interface HttpStart {
|
||||
fetch: <T>(...args: any) => any;
|
||||
}
|
||||
|
||||
export interface ApiParams {
|
||||
http: HttpStart;
|
||||
signal: AbortSignal;
|
||||
}
|
||||
export type ApiPayload<T extends ApiParams> = Omit<T, 'http' | 'signal'>;
|
||||
|
||||
export interface FindListsParams extends ApiParams {
|
||||
cursor?: string | undefined;
|
||||
pageSize: number | undefined;
|
||||
pageIndex: number | undefined;
|
||||
}
|
||||
|
||||
export interface ImportListParams extends ApiParams {
|
||||
file: File;
|
||||
listId: string | undefined;
|
||||
type: Type | undefined;
|
||||
}
|
||||
|
||||
export interface DeleteListParams extends ApiParams {
|
||||
deleteReferences?: boolean;
|
||||
id: string;
|
||||
ignoreReferences?: boolean;
|
||||
}
|
||||
|
||||
export interface ExportListParams extends ApiParams {
|
||||
listId: string;
|
||||
}
|
19
packages/kbn-securitysolution-list-api/tsconfig.json
Normal file
19
packages/kbn-securitysolution-list-api/tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"incremental": true,
|
||||
"outDir": "target",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true,
|
||||
"sourceRoot": "../../../../packages/kbn-securitysolution-list-api/src",
|
||||
"types": [
|
||||
"jest",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue